diff options
Diffstat (limited to 'tests')
339 files changed, 13206 insertions, 1596 deletions
diff --git a/tests/RUNNING_TESTS.md b/tests/RUNNING_TESTS.md index afd7caa709..b082197166 100644 --- a/tests/RUNNING_TESTS.md +++ b/tests/RUNNING_TESTS.md @@ -120,8 +120,9 @@ directory (above phpBB): Slow tests -------------- -Certain tests, such as the UTF-8 normalizer or the DNS tests tend to be slow. -Thus these tests are in the `slow` group, which is excluded by default. If you +Certain tests, such as the DNS tests tend to be slow. +Thus these tests are in the `slow` group, which is excluded by default. You can +enable slow tests by copying the phpunit.xml.all file to phpunit.xml. If you only want the slow tests, run: $ phpBB/vendor/bin/phpunit --group slow diff --git a/tests/attachment/delete_test.php b/tests/attachment/delete_test.php new file mode 100644 index 0000000000..f1835dd37a --- /dev/null +++ b/tests/attachment/delete_test.php @@ -0,0 +1,127 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once(dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php'); + +class phpbb_attachment_delete_test extends \phpbb_database_test_case +{ + /** @var \phpbb\config\config */ + protected $config; + + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** @var \phpbb\filesystem\filesystem */ + protected $filesystem; + + /** @var \phpbb\attachment\resync */ + protected $resync; + + /** @var \phpbb\attachment\delete */ + protected $attachment_delete; + + protected $phpbb_root_path; + + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml'); + } + + public function setUp() + { + global $db, $phpbb_root_path; + + parent::setUp(); + + $this->config = new \phpbb\config\config(array()); + $this->db = $this->new_dbal(); + $db = $this->db; + $this->resync = new \phpbb\attachment\resync($this->db); + $this->filesystem = $this->getMock('\phpbb\filesystem\filesystem', array('remove', 'exists')); + $this->filesystem->expects($this->any()) + ->method('remove') + ->willReturn(false); + $this->filesystem->expects($this->any()) + ->method('exists') + ->willReturn(true); + $this->phpbb_root_path = $phpbb_root_path; + $this->dispatcher = new \phpbb_mock_event_dispatcher(); + $this->attachment_delete = new \phpbb\attachment\delete($this->config, $this->db, $this->dispatcher, $this->filesystem, $this->resync, $phpbb_root_path); + } + + public function data_attachment_delete() + { + return array( + array('attach', '', false, false), + array('meh', 5, false, 0), + array('attach', array(5), false, 0), + array('attach', array(1,2), false, 2), + array('attach', array(1,2), true, 2), + array('post', 5, false, 0), + array('topic', 5, false, 0), + array('topic', 1, true, 3), + array('user', 1, false, 0), + ); + } + + /** + * @dataProvider data_attachment_delete + */ + public function test_attachment_delete($mode, $ids, $resync, $expected) + { + // We need to reset the attachment ID sequence to properly test this + if ($this->db->get_sql_layer() === 'postgres') + { + $sql = 'ALTER SEQUENCE phpbb_attachments_seq RESTART WITH 1'; + $this->db->sql_query($sql); + } + + $this->assertSame($expected, $this->attachment_delete->delete($mode, $ids, $resync)); + } + + public function data_attachment_unlink() + { + return array( + array(true, true, true), + array(true, false, false), + array(true, true, false, true), + ); + } + + /** + * @dataProvider data_attachment_unlink + */ + public function test_attachment_delete_success($remove_success, $exists_success, $expected, $throw_exception = false) + { + $this->filesystem = $this->getMock('\phpbb\filesystem\filesystem', array('remove', 'exists')); + if ($throw_exception) + { + $this->filesystem->expects($this->any()) + ->method('remove') + ->willThrowException(new \phpbb\filesystem\exception\filesystem_exception);; + } + else + { + $this->filesystem->expects($this->any()) + ->method('remove') + ->willReturn($remove_success); + } + + $this->filesystem->expects($this->any()) + ->method('exists') + ->willReturn($exists_success); + + $this->attachment_delete = new \phpbb\attachment\delete($this->config, $this->db, $this->dispatcher, $this->filesystem, $this->resync, $this->phpbb_root_path); + $this->assertSame($expected, $this->attachment_delete->unlink_attachment('foobar')); + } +} diff --git a/tests/attachment/fixtures/resync.xml b/tests/attachment/fixtures/resync.xml new file mode 100644 index 0000000000..6e2cc62f68 --- /dev/null +++ b/tests/attachment/fixtures/resync.xml @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_attachments"> + <column>post_msg_id</column> + <column>topic_id</column> + <column>in_message</column> + <column>is_orphan</column> + <column>attach_comment</column> + <column>physical_filename</column> + <column>thumbnail</column> + <row> + <value>1</value> + <value>1</value> + <value>0</value> + <value>0</value> + <value>foo</value> + <value>foo</value> + <value>0</value> + </row> + <row> + <value>1</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value>foo2</value> + <value>foo2</value> + <value>0</value> + </row> + <row> + <value>1</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value>foo2</value> + <value>foo2</value> + <value>1</value> + </row> + </table> + <table name="phpbb_extensions"> + <column>extension</column> + <column>group_id</column> + <row> + <value>jpg</value> + <value>1</value> + </row> + <row> + <value>png</value> + <value>1</value> + </row> + </table> + <table name="phpbb_extension_groups"> + <column>cat_id</column> + <column>group_id</column> + <column>download_mode</column> + <column>upload_icon</column> + <column>max_filesize</column> + <column>allow_group</column> + <column>allow_in_pm</column> + <column>allowed_forums</column> + <column>group_name</column> + <row> + <value>1</value> + <value>1</value> + <value>1</value> + <value> </value> + <value>1000</value> + <value>1</value> + <value>1</value> + <value>a:1:{i:0;i:1;}</value> + <value>Images</value> + </row> + </table> + <table name="phpbb_posts"> + <column>post_id</column> + <column>post_text</column> + <column>poster_id</column> + <column>post_attachment</column> + <row> + <value>1</value> + <value>foo</value> + <value>1</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>foo</value> + <value>1</value> + <value>1</value> + </row> + </table> + <table name="phpbb_privmsgs"> + <column>msg_id</column> + <column>message_text</column> + <column>message_attachment</column> + <column>to_address</column> + <column>bcc_address</column> + <row> + <value>1</value> + <value>foo</value> + <value>1</value> + <value>2</value> + <value>2</value> + </row> + <row> + <value>2</value> + <value>foo</value> + <value>1</value> + <value>2</value> + <value>2</value> + </row> + </table> + <table name="phpbb_topics"> + <column>topic_id</column> + <column>forum_id</column> + <column>topic_title</column> + <column>topic_attachment</column> + <row> + <value>1</value> + <value>1</value> + <value>foo</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>1</value> + <value>bar</value> + <value>1</value> + </row> + </table> +</dataset> diff --git a/tests/attachment/manager_test.php b/tests/attachment/manager_test.php new file mode 100644 index 0000000000..47d7f38b1d --- /dev/null +++ b/tests/attachment/manager_test.php @@ -0,0 +1,131 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_attachment_manager_test extends \phpbb_test_case +{ + protected $delete; + protected $resync; + protected $upload; + + public function setUp() + { + $this->delete = $this->getMockBuilder('\phpbb\attachment\delete') + ->disableOriginalConstructor() + ->setMethods(['delete', 'unlink_attachment']) + ->getMock(); + $this->resync = $this->getMockBuilder('\phpbb\attachment\resync') + ->disableOriginalConstructor() + ->setMethods(['resync']) + ->getMock(); + $this->upload = $this->getMockBuilder('\phpbb\attachment\upload') + ->disableOriginalConstructor() + ->setMethods(['upload']) + ->getMock(); + } + + protected function get_manager() + { + return new \phpbb\attachment\manager($this->delete, $this->resync, $this->upload); + } + + public function data_manager() + { + return array( + array( + 'delete', + 'unlink_attachment', + 'unlink', + ['foo'], + ['foo', 'file', false], + true, + true, + ), + array( + 'delete', + 'unlink_attachment', + 'unlink', + ['foo', 'bar'], + ['foo', 'bar', false], + true, + true, + ), + array( + 'delete', + 'unlink_attachment', + 'unlink', + ['foo', 'bar', true], + ['foo', 'bar', true], + true, + true, + ), + array( + 'delete', + 'delete', + 'delete', + ['foo', [1, 2, 3]], + ['foo', [1, 2, 3], true], + 5, + 5, + ), + array( + 'delete', + 'delete', + 'delete', + ['foo', [1, 2, 3], false], + ['foo', [1, 2, 3], false], + 2, + 2, + ), + array( + 'resync', + 'resync', + 'resync', + ['foo', [1, 2, 3]], + ['foo', [1, 2, 3]], + true, + null, + ), + array( + 'upload', + 'upload', + 'upload', + ['foo', 1], + ['foo', 1, false, '', false, []], + true, + true, + ), + array( + 'upload', + 'upload', + 'upload', + ['foo', 1, true, 'bar', true, ['filename' => 'foobar']], + ['foo', 1, true, 'bar', true, ['filename' => 'foobar']], + true, + true, + ), + ); + } + + /** + * @dataProvider data_manager + */ + public function test_manager($class, $method_class, $method_manager, $input_manager, $input_method, $return, $output) + { + $mock = call_user_func_array([$this->{$class}, 'expects'], [$this->atLeastOnce()]); + $mock = $mock->method($method_class); + $mock = call_user_func_array([$mock, 'with'], $input_method); + $mock->willReturn($return); + $manager = $this->get_manager(); + $this->assertSame($output, call_user_func_array([$manager, $method_manager], $input_manager)); + } +} diff --git a/tests/attachment/resync_test.php b/tests/attachment/resync_test.php new file mode 100644 index 0000000000..f882af9ae5 --- /dev/null +++ b/tests/attachment/resync_test.php @@ -0,0 +1,74 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +class phpbb_attachment_resync_test extends \phpbb_database_test_case +{ + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** @var \phpbb\attachment\resync */ + protected $resync; + + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml'); + } + + public function setUp() + { + parent::setUp(); + + $this->db = $this->new_dbal(); + $this->resync = new \phpbb\attachment\resync($this->db); + } + + public function data_resync() + { + return array( + array('', array(1), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '1')), + array('post', array(1), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '1')), + array('post', array(2), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '0')), + array('topic', array(1), 'topic_id', TOPICS_TABLE, array('topic_attachment' => '1'), array('topic_attachment' => '1')), + array('topic', array(2), 'topic_id', TOPICS_TABLE, array('topic_attachment' => '1'), array('topic_attachment' => '0')), + array('message', array(1), 'msg_id', PRIVMSGS_TABLE, array('message_attachment' => '1'), array('message_attachment' => '1')), + array('message', array(2), 'msg_id', PRIVMSGS_TABLE, array('message_attachment' => '1'), array('message_attachment' => '0')), + ); + } + + /** + * @dataProvider data_resync + */ + public function test_resync($type, $ids, $sql_id, $exist_table, $exist_data, $resync_data) + { + $sql_prefix = ($type) ?: 'post'; + $sql = 'SELECT ' . $sql_prefix . '_attachment + FROM ' . $exist_table . ' + WHERE ' . $sql_id . ' = ' . $ids[0]; + $result = $this->db->sql_query($sql); + $data = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->assertEquals($exist_data, $data); + + $this->resync->resync($type, $ids); + + $sql = 'SELECT ' . $sql_prefix . '_attachment + FROM ' . $exist_table . ' + WHERE ' . $sql_id . ' = ' . $ids[0]; + $result = $this->db->sql_query($sql); + $data = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->assertEquals($resync_data, $data); + } +} diff --git a/tests/attachment/upload_test.php b/tests/attachment/upload_test.php new file mode 100644 index 0000000000..295b6b15c9 --- /dev/null +++ b/tests/attachment/upload_test.php @@ -0,0 +1,430 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once(dirname(__FILE__) . '/../../phpBB/includes/functions.php'); +require_once(dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php'); + +class phpbb_attachment_upload_test extends \phpbb_database_test_case +{ + /** @var \phpbb\auth\auth */ + protected $auth; + + /** @var \phpbb\cache\service */ + protected $cache; + + /** @var \phpbb\config\config */ + protected $config; + + /** @var \phpbb\files\upload */ + protected $files_upload; + + /** @var \phpbb\language\language */ + protected $language; + + /** @var \phpbb\mimetype\guesser */ + protected $mimetype_guesser; + + /** @var \phpbb\event\dispatcher */ + protected $phpbb_dispatcher; + + /** @var \phpbb\plupload\plupload */ + protected $plupload; + + /** @var \phpbb\user */ + protected $user; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** @var \phpbb\attachment\upload */ + protected $upload; + + private $filesystem; + + /** @var \Symfony\Component\DependencyInjection\ContainerInterface */ + protected $container; + + /** @var \phpbb\files\factory */ + protected $factory; + + /** @var \bantu\IniGetWrapper\IniGetWrapper */ + protected $php_ini; + + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml'); + } + + public function setUp() + { + global $config, $phpbb_root_path, $phpEx; + + parent::setUp(); + + $this->auth = new \phpbb\auth\auth(); + $this->config = new \phpbb\config\config(array( + 'upload_path' => '', + 'img_create_thumbnail' => true, + )); + $config = $this->config; + $this->db = $this->new_dbal(); + $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\dummy(), $this->config, $this->db, $phpbb_root_path, $phpEx); + $this->request = $this->getMock('\phpbb\request\request'); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper; + $guessers = array( + new \Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser(), + new \Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser(), + new \phpbb\mimetype\content_guesser(), + new \phpbb\mimetype\extension_guesser(), + ); + $guessers[2]->set_priority(-2); + $guessers[3]->set_priority(-2); + $this->mimetype_guesser = new \phpbb\mimetype\guesser($guessers); + $this->plupload = new \phpbb\plupload\plupload($phpbb_root_path, $this->config, $this->request, new \phpbb\user($this->language, '\phpbb\datetime'), $this->php_ini, $this->mimetype_guesser); + $factory_mock = $this->getMockBuilder('\phpbb\files\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory_mock->expects($this->any()) + ->method('get') + ->willReturn(new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $this->phpbb_root_path, + $this->mimetype_guesser + )); + + $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx); + $this->container->set('files.filespec', new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + )))); + $this->container->set('files.types.form', new \phpbb\files\types\form( + $factory_mock, + $this->language, + $this->php_ini, + $this->plupload, + $this->request + )); + $this->container->set('files.types.local', new \phpbb\files\types\local( + $factory_mock, + $this->language, + $this->php_ini, + $this->request + )); + $this->factory = new \phpbb\files\factory($this->container); + $this->files_upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $this->phpbb_dispatcher = new phpbb_mock_event_dispatcher(); + $this->user = new \phpbb\user($this->language, '\phpbb\datetime'); + + + $this->upload = new \phpbb\attachment\upload( + $this->auth, + $this->cache, + $this->config, + $this->files_upload, + $this->language, + $this->mimetype_guesser, + $this->phpbb_dispatcher, + $this->plupload, + $this->user, + $this->phpbb_root_path + ); + } + + public function data_upload() + { + return array( + array('foobar', 1, false, + array(), + array( + 'error' => array( + 'Upload initiated but no valid file upload form found.', + ), + 'post_attach' => false, + ) + ), + array('foobar', 1, true, + array( + 'realname' => 'foobar.jpg', + 'type' => 'jpg', + 'size' => 100, + ), + array( + 'error' => array( + 'NOT_UPLOADED', + 'The image file you tried to attach is invalid.', + ), + 'post_attach' => false, + 'thumbnail' => 1, + ) + ), + array('foobar', 1, true, + array(), + array( + 'error' => array( + 'NOT_UPLOADED', + ), + 'post_attach' => false, + 'thumbnail' => 0, + ) + ), + ); + } + + /** + * @dataProvider data_upload + */ + public function test_upload($form_name, $forum_id, $local, $filedata, $expected) + { + $filedata = $this->upload->upload($form_name, $forum_id, $local, '', false, $filedata); + + $this->assertSame($expected, $filedata); + } + + public function test_init_error() + { + $filespec = $this->getMockBuilder('\phpbb\files\filespec') + ->disableOriginalConstructor() + ->getMock(); + $filespec->expects($this->any()) + ->method('init_error') + ->willReturn(true); + $filespec->expects($this->any()) + ->method('set_upload_namespace') + ->willReturnSelf(); + $filespec->expects($this->any()) + ->method('set_upload_ary') + ->willReturnSelf(); + $this->container->set('files.filespec', $filespec); + $factory_mock = $this->getMockBuilder('\phpbb\files\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory_mock->expects($this->any()) + ->method('get') + ->willReturn($filespec); + $this->container->set('files.types.local', new \phpbb\files\types\local( + $factory_mock, + $this->language, + $this->php_ini, + $this->request + )); + + $this->upload = new \phpbb\attachment\upload( + $this->auth, + $this->cache, + $this->config, + $this->files_upload, + $this->language, + $this->mimetype_guesser, + $this->phpbb_dispatcher, + $this->plupload, + $this->user, + $this->phpbb_root_path + ); + + $filedata = $this->upload->upload('foobar', 1, true); + + $this->assertSame(array( + 'error' => array(), + 'post_attach' => false, + ), $filedata); + } + + public function data_image_upload() + { + return array( + array(false, false, array(), + array( + 'error' => array('The image file you tried to attach is invalid.'), + 'post_attach' => false, + 'thumbnail' => 1, + ) + ), + array(false, true, array(), + array( + 'error' => array('The image file you tried to attach is invalid.'), + 'post_attach' => false, + 'thumbnail' => 1, + ) + ), + array(true, false, array(), + array( + 'error' => array(), + 'post_attach' => true, + // thumbnail gets reset to 0 as creation was not possible + 'thumbnail' => 0, + 'filesize' => 100, + 'mimetype' => 'jpg', + 'extension' => 'jpg', + 'real_filename' => 'foobar.jpg', + ) + ), + array(true, false, + array( + 'check_attachment_content' => true, + 'mime_triggers' => '', + ), + array( + 'error' => array(), + 'post_attach' => true, + // thumbnail gets reset to 0 as creation was not possible + 'thumbnail' => 0, + 'filesize' => 100, + 'mimetype' => 'jpg', + 'extension' => 'jpg', + 'real_filename' => 'foobar.jpg', + ) + ), + array(true, false, + array( + 'attachment_quota' => 150, + ), + array( + 'error' => array(), + 'post_attach' => true, + // thumbnail gets reset to 0 as creation was not possible + 'thumbnail' => 0, + 'filesize' => 100, + 'mimetype' => 'jpg', + 'extension' => 'jpg', + 'real_filename' => 'foobar.jpg', + ) + ), + array(true, false, + array( + 'attachment_quota' => 50, + ), + array( + 'error' => array( + 'ATTACH_QUOTA_REACHED', + ), + 'post_attach' => false, + 'thumbnail' => 1, + 'filesize' => 100, + 'mimetype' => 'jpg', + 'extension' => 'jpg', + 'real_filename' => 'foobar.jpg', + ) + ), + ); + } + + /** + * @dataProvider data_image_upload + */ + public function test_image_upload($is_image, $plupload_active, $config_data, $expected) + { + $filespec = $this->getMock('\phpbb\files\filespec', + array( + 'init_error', + 'is_image', + 'move_file', + 'is_uploaded', + ), + array( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $this->phpbb_root_path, + $this->mimetype_guesser, + $this->plupload + )); + foreach ($config_data as $key => $value) + { + $this->config[$key] = $value; + } + $filespec->set_upload_namespace($this->files_upload); + $filespec->expects($this->any()) + ->method('init_error') + ->willReturn(false); + $filespec->expects($this->any()) + ->method('is_image') + ->willReturn($is_image); + $filespec->expects($this->any()) + ->method('is_uploaded') + ->willReturn(true); + $filespec->expects($this->any()) + ->method('move_file') + ->willReturn(false); + $this->container->set('files.filespec', $filespec); + $factory_mock = $this->getMockBuilder('\phpbb\files\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory_mock->expects($this->any()) + ->method('get') + ->willReturn($filespec); + $this->container->set('files.types.local', new \phpbb\files\types\local( + $factory_mock, + $this->language, + $this->php_ini, + $this->request + )); + + $plupload = $this->getMockBuilder('\phpbb\plupload\plupload') + ->disableOriginalConstructor() + ->getMock(); + $plupload->expects($this->any()) + ->method('is_active') + ->willReturn($plupload_active); + if ($plupload_active) + { + $plupload->expects($this->once()) + ->method('emit_error') + ->with(104, 'ATTACHED_IMAGE_NOT_IMAGE') + ->willReturn(false); + } + $this->upload = new \phpbb\attachment\upload( + $this->auth, + $this->cache, + $this->config, + $this->files_upload, + $this->language, + $this->mimetype_guesser, + $this->phpbb_dispatcher, + $plupload, + $this->user, + $this->phpbb_root_path + ); + + $filedata = $this->upload->upload('foobar', 1, true, '', false, array( + 'realname' => 'foobar.jpg', + 'type' => 'jpg', + 'size' => 100, + )); + + foreach ($expected as $key => $entry) + { + $this->assertEquals($entry, $filedata[$key]); + } + + // Reset config data + foreach ($config_data as $key => $value) + { + $this->config->delete($key); + } + } +} diff --git a/tests/auth/provider_apache_test.php b/tests/auth/provider_apache_test.php index 68ad7b2c19..60423acbc1 100644 --- a/tests/auth/provider_apache_test.php +++ b/tests/auth/provider_apache_test.php @@ -28,8 +28,10 @@ class phpbb_auth_provider_apache_test extends phpbb_database_test_case $db = $this->new_dbal(); $config = new \phpbb\config\config(array()); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); $this->request = $this->getMock('\phpbb\request\request'); - $this->user = new \phpbb\user('\phpbb\datetime'); + $this->user = new \phpbb\user($lang, '\phpbb\datetime'); $driver_helper = new \phpbb\passwords\driver\helper($config); $passwords_drivers = array( 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $driver_helper), diff --git a/tests/auth/provider_db_test.php b/tests/auth/provider_db_test.php index 09ca0816bf..38dbfa1fcb 100644 --- a/tests/auth/provider_db_test.php +++ b/tests/auth/provider_db_test.php @@ -38,8 +38,10 @@ class phpbb_auth_provider_db_test extends phpbb_database_test_case 'ip_login_limit_use_forwarded' => 0, 'max_login_attempts' => 0, )); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); $request = $this->getMock('\phpbb\request\request'); - $user = new \phpbb\user('\phpbb\datetime'); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $driver_helper = new \phpbb\passwords\driver\helper($config); $passwords_drivers = array( 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $driver_helper), diff --git a/tests/auth/provider_oauth_token_storage_test.php b/tests/auth/provider_oauth_token_storage_test.php index 71b49ff439..ae5de6aa7e 100644 --- a/tests/auth/provider_oauth_token_storage_test.php +++ b/tests/auth/provider_oauth_token_storage_test.php @@ -22,6 +22,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c protected $session_id; protected $token_storage; protected $token_storage_table; + protected $state_table; protected $user; protected function setup() @@ -31,9 +32,12 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c global $phpbb_root_path, $phpEx; $this->db = $this->new_dbal(); - $this->user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $this->user = new \phpbb\user($lang, '\phpbb\datetime'); $this->service_name = 'auth.provider.oauth.service.testing'; $this->token_storage_table = 'phpbb_oauth_tokens'; + $this->state_table = 'phpbb_oauth_states'; // Give the user a session_id that we will remember $this->session_id = '12345'; @@ -42,7 +46,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c // Set the user id to anonymous $this->user->data['user_id'] = ANONYMOUS; - $this->token_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table); + $this->token_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table, $this->state_table); } public function getDataSet() @@ -96,7 +100,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c $expected_token = new StdOAuth2Token('access', 'refresh', StdOAuth2Token::EOL_NEVER_EXPIRES); // Store a token in the database - $temp_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table); + $temp_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table, $this->state_table); $temp_storage->storeAccessToken($this->service_name, $expected_token); unset($temp_storage); @@ -127,7 +131,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c $expected_token = new StdOAuth2Token('access', 'refresh', StdOAuth2Token::EOL_NEVER_EXPIRES); // Store a token in the database - $temp_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table); + $temp_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table, $this->state_table); $temp_storage->storeAccessToken($this->service_name, $expected_token); unset($temp_storage); diff --git a/tests/avatar/driver/barfoo.php b/tests/avatar/driver/barfoo.php index 0bf30b8a91..067bb3ef97 100644 --- a/tests/avatar/driver/barfoo.php +++ b/tests/avatar/driver/barfoo.php @@ -1,26 +1,26 @@ -<?php
-
-namespace phpbb\avatar\driver;
-
-class barfoo extends \phpbb\avatar\driver\driver
-{
- public function get_data($row)
- {
- return array();
- }
-
- public function prepare_form($request, $template, $user, $row, &$error)
- {
- return false;
- }
-
- public function process_form($request, $template, $user, $row, &$error)
- {
- return false;
- }
-
- public function get_template_name()
- {
- return 'barfoo.html';
- }
-}
+<?php + +namespace phpbb\avatar\driver; + +class barfoo extends \phpbb\avatar\driver\driver +{ + public function get_data($row) + { + return array(); + } + + public function prepare_form($request, $template, $user, $row, &$error) + { + return false; + } + + public function process_form($request, $template, $user, $row, &$error) + { + return false; + } + + public function get_template_name() + { + return 'barfoo.html'; + } +} diff --git a/tests/avatar/driver/foobar.php b/tests/avatar/driver/foobar.php index aabdaf5ac4..16d50ccad4 100644 --- a/tests/avatar/driver/foobar.php +++ b/tests/avatar/driver/foobar.php @@ -1,26 +1,26 @@ -<?php
-
-namespace phpbb\avatar\driver;
-
-class foobar extends \phpbb\avatar\driver\driver
-{
- public function get_data($row)
- {
- return array();
- }
-
- public function prepare_form($request, $template, $user, $row, &$error)
- {
- return false;
- }
-
- public function process_form($request, $template, $user, $row, &$error)
- {
- return false;
- }
-
- public function get_template_name()
- {
- return 'foobar.html';
- }
-}
+<?php + +namespace phpbb\avatar\driver; + +class foobar extends \phpbb\avatar\driver\driver +{ + public function get_data($row) + { + return array(); + } + + public function prepare_form($request, $template, $user, $row, &$error) + { + return false; + } + + public function process_form($request, $template, $user, $row, &$error) + { + return false; + } + + public function get_template_name() + { + return 'foobar.html'; + } +} diff --git a/tests/avatar/manager_test.php b/tests/avatar/manager_test.php index 344eef38ff..924f1319a2 100644 --- a/tests/avatar/manager_test.php +++ b/tests/avatar/manager_test.php @@ -35,6 +35,8 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case ->method('get') ->will($this->returnArgument(0)); + $filesystem = new \phpbb\filesystem\filesystem(); + // Prepare dependencies for avatar manager and driver $this->config = new \phpbb\config\config(array()); $cache = $this->getMock('\phpbb\cache\driver\driver_interface'); @@ -42,7 +44,7 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + $filesystem, $this->getMock('\phpbb\request\request'), $phpbb_root_path, $phpEx @@ -55,11 +57,12 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case new \phpbb\mimetype\content_guesser, ); $guesser = new \phpbb\mimetype\guesser($guessers); + $imagesize = new \FastImageSize\FastImageSize(); $dispatcher = new phpbb_mock_event_dispatcher(); // $this->avatar_foobar will be needed later on - $this->avatar_foobar = $this->getMock('\phpbb\avatar\driver\foobar', array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $path_helper, $cache)); + $this->avatar_foobar = $this->getMock('\phpbb\avatar\driver\foobar', array('get_name'), array($this->config, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache)); $this->avatar_foobar->expects($this->any()) ->method('get_name') ->will($this->returnValue('avatar.driver.foobar')); @@ -73,15 +76,17 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case ->will($this->returnValue('barfoo')); $avatar_drivers = array($this->avatar_foobar, $this->avatar_barfoo); + $files_factory = new \phpbb\files\factory($phpbb_container); + foreach ($this->avatar_drivers() as $driver) { if ($driver !== 'upload') { - $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $path_helper, $cache)); + $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache)); } else { - $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $path_helper, $guesser, $dispatcher, $cache)); + $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $filesystem, $path_helper, $dispatcher, $files_factory, $cache)); } $cur_avatar->expects($this->any()) ->method('get_name') @@ -96,7 +101,9 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case // Set up avatar manager $this->manager = new \phpbb\avatar\manager($this->config, $avatar_drivers, $phpbb_container); $this->db = $this->new_dbal(); - $this->user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $this->user = new \phpbb\user($lang, '\phpbb\datetime'); } protected function avatar_drivers() @@ -279,7 +286,12 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case public function test_localize_errors() { - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + global $phpbb_root_path, $phpEx; + + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime') + ); $lang_array = array( array('FOOBAR_OFF', 'foobar_off'), array('FOOBAR_EXPLAIN', 'FOOBAR_EXPLAIN %s'), diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 0e81f4372a..86e1e5314b 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -12,8 +12,12 @@ */ define('IN_PHPBB', true); +define('PHPBB_ENVIRONMENT', 'test'); + $phpbb_root_path = 'phpBB/'; $phpEx = 'php'; + +global $table_prefix; require_once $phpbb_root_path . 'includes/startup.php'; $table_prefix = 'phpbb_'; diff --git a/tests/cache/apc_driver_test.php b/tests/cache/apc_driver_test.php index 10130b465b..706f274448 100644 --- a/tests/cache/apc_driver_test.php +++ b/tests/cache/apc_driver_test.php @@ -34,14 +34,14 @@ class phpbb_cache_apc_driver_test extends phpbb_cache_common_test_case self::markTestSkipped('APC extension is not loaded'); } - $php_ini = new \phpbb\php\ini; + $php_ini = new \bantu\IniGetWrapper\IniGetWrapper; - if (!$php_ini->get_bool('apc.enabled')) + if (!$php_ini->getBool('apc.enabled')) { self::markTestSkipped('APC is not enabled. Make sure apc.enabled=1 in php.ini'); } - if (PHP_SAPI == 'cli' && !$php_ini->get_bool('apc.enable_cli')) + if (PHP_SAPI == 'cli' && !$php_ini->getBool('apc.enable_cli')) { self::markTestSkipped('APC is not enabled for CLI. Set apc.enable_cli=1 in php.ini'); } diff --git a/tests/cache/null_driver_test.php b/tests/cache/dummy_driver_test.php index b9f96732f5..6cb6b73729 100644 --- a/tests/cache/null_driver_test.php +++ b/tests/cache/dummy_driver_test.php @@ -11,7 +11,7 @@ * */ -class phpbb_cache_null_driver_test extends phpbb_database_test_case +class phpbb_cache_dummy_driver_test extends phpbb_database_test_case { protected $driver; @@ -24,7 +24,7 @@ class phpbb_cache_null_driver_test extends phpbb_database_test_case { parent::setUp(); - $this->driver = new \phpbb\cache\driver\null; + $this->driver = new \phpbb\cache\driver\dummy; } public function test_get_put() diff --git a/tests/captcha/qa_test.php b/tests/captcha/qa_test.php index 1f2f9f3070..4aa5e714f5 100644 --- a/tests/captcha/qa_test.php +++ b/tests/captcha/qa_test.php @@ -27,14 +27,16 @@ class phpbb_captcha_qa_test extends \phpbb_database_test_case public function setUp() { - global $db; + global $db, $request, $phpbb_container; $db = $this->new_dbal(); parent::setUp(); - $this->request = new \phpbb_mock_request(); - request_var(false, false, false, false, $this->request); + $request = new \phpbb_mock_request(); + $phpbb_container = new \phpbb_mock_container_builder(); + $factory = new \phpbb\db\tools\factory(); + $phpbb_container->set('dbal.tools', $factory->get($db)); $this->qa = new \phpbb\captcha\plugins\qa('phpbb_captcha_questions', 'phpbb_captcha_answers', 'phpbb_qa_confirm'); } @@ -87,7 +89,8 @@ class phpbb_captcha_qa_test extends \phpbb_database_test_case */ public function test_acp_get_question_input($value, $expected) { - $this->request->overwrite('answers', $value); + global $request; + $request->overwrite('answers', $value); $this->assertEquals($expected, $this->qa->acp_get_question_input()); } diff --git a/tests/composer.json b/tests/composer.json deleted file mode 100644 index 69512f30a6..0000000000 --- a/tests/composer.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "require-dev": { - "facebook/webdriver": "dev-master" - } -} diff --git a/tests/composer.lock b/tests/composer.lock deleted file mode 100644 index f714495d84..0000000000 --- a/tests/composer.lock +++ /dev/null @@ -1,66 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" - ], - "hash": "cf1d8a4841e5e669b148e0df6645a788", - "packages": [ - - ], - "packages-dev": [ - { - "name": "facebook/webdriver", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/facebook/php-webdriver.git", - "reference": "b6e002e5bf811a8edba393ce6872322c1b7cf796" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/b6e002e5bf811a8edba393ce6872322c1b7cf796", - "reference": "b6e002e5bf811a8edba393ce6872322c1b7cf796", - "shasum": "" - }, - "require": { - "php": ">=5.3.19" - }, - "require-dev": { - "phpdocumentor/phpdocumentor": "2.*", - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "autoload": { - "classmap": [ - "lib/" - ] - }, - "notification-url": "http://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "description": "A php client for WebDriver", - "homepage": "https://github.com/facebook/php-webdriver", - "keywords": [ - "facebook", - "php", - "selenium", - "webdriver" - ], - "time": "2014-08-05 02:55:46" - } - ], - "aliases": [ - - ], - "minimum-stability": "stable", - "stability-flags": { - "facebook/webdriver": 20 - }, - "platform": [ - - ], - "platform-dev": [ - - ] -} diff --git a/tests/console/cache/purge_test.php b/tests/console/cache/purge_test.php index 96988c1028..6c92660580 100644 --- a/tests/console/cache/purge_test.php +++ b/tests/console/cache/purge_test.php @@ -32,6 +32,8 @@ class phpbb_console_command_cache_purge_test extends phpbb_test_case protected function setUp() { + global $phpbb_root_path, $phpEx; + if (file_exists($this->cache_dir)) { // cache directory possibly left after aborted @@ -45,7 +47,10 @@ class phpbb_console_command_cache_purge_test extends phpbb_test_case $this->db = $this->getMock('\phpbb\db\driver\driver_interface'); $this->config = new \phpbb\config\config(array('assets_version' => 1)); - $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $this->user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime') + ); } public function test_purge() @@ -86,7 +91,7 @@ class phpbb_console_command_cache_purge_test extends phpbb_test_case public function get_command_tester() { $application = new Application(); - $application->add(new purge($this->user, $this->cache, $this->db, $this->getMock('\phpbb\auth\auth'), new \phpbb\log\null(), $this->config)); + $application->add(new purge($this->user, $this->cache, $this->db, $this->getMock('\phpbb\auth\auth'), new \phpbb\log\dummy(), $this->config)); $command = $application->find('cache:purge'); $this->command_name = $command->getName(); diff --git a/tests/console/config/config_test.php b/tests/console/config/config_test.php index 7c098af004..076316217d 100644 --- a/tests/console/config/config_test.php +++ b/tests/console/config/config_test.php @@ -22,9 +22,14 @@ class phpbb_console_command_config_test extends phpbb_test_case public function setUp() { + global $phpbb_root_path, $phpEx; + $this->config = new \phpbb\config\config(array()); - $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $this->user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime') + ); $this->user->method('lang')->will($this->returnArgument(0)); } diff --git a/tests/console/cron/cron_list_test.php b/tests/console/cron/cron_list_test.php index 22423304be..3bbe2078ba 100644 --- a/tests/console/cron/cron_list_test.php +++ b/tests/console/cron/cron_list_test.php @@ -32,7 +32,12 @@ class phpbb_console_command_cron_list_test extends phpbb_test_case protected function setUp() { - $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + global $phpbb_root_path, $phpEx; + + $this->user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $this->user->method('lang')->will($this->returnArgument(0)); } diff --git a/tests/console/cron/run_test.php b/tests/console/cron/run_test.php index f76e967484..d6c7b21781 100644 --- a/tests/console/cron/run_test.php +++ b/tests/console/cron/run_test.php @@ -39,10 +39,12 @@ class phpbb_console_command_cron_run_test extends phpbb_database_test_case $db = $this->db = $this->new_dbal(); $config = $this->config = new \phpbb\config\config(array('cron_lock' => '0')); - set_config(null, null, null, $this->config); $this->lock = new \phpbb\lock\db('cron_lock', $this->config, $this->db); - $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $this->user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $this->user->method('lang')->will($this->returnArgument(0)); $this->task = new phpbb_cron_task_simple(); @@ -76,6 +78,10 @@ class phpbb_console_command_cron_run_test extends phpbb_database_test_case $this->assertSame(false, $this->lock->owns_lock()); } + /** + * @expectedException \phpbb\exception\runtime_exception + * @expectedExceptionMessage CRON_LOCK_ERROR + */ public function test_error_lock() { $this->lock->acquire(); @@ -124,6 +130,10 @@ class phpbb_console_command_cron_run_test extends phpbb_database_test_case $this->assertSame(false, $this->lock->owns_lock()); } + /** + * @expectedException \phpbb\exception\runtime_exception + * @expectedExceptionMessage CRON_NO_SUCH_TASK + */ public function test_arg_invalid() { $command_tester = $this->get_command_tester(); diff --git a/tests/console/fixtures/png.png b/tests/console/fixtures/png.png Binary files differnew file mode 100644 index 0000000000..c143a26a06 --- /dev/null +++ b/tests/console/fixtures/png.png diff --git a/tests/console/fixtures/thumbnail.xml b/tests/console/fixtures/thumbnail.xml new file mode 100644 index 0000000000..8037523633 --- /dev/null +++ b/tests/console/fixtures/thumbnail.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_attachments"> + <column>attach_id</column> + <column>physical_filename</column> + <column>real_filename</column> + <column>thumbnail</column> + <column>extension</column> + <column>mimetype</column> + <column>attach_comment</column> + + <row> + <value>1</value> + <value>test_png_1</value> + <value>real_test.png</value> + <value>0</value> + <value>png</value> + <value>image/png</value> + <value></value> + </row> + <row> + <value>2</value> + <value>test_png_2</value> + <value>real_test.png</value> + <value>1</value> + <value>png</value> + <value>image/png</value> + <value></value> + </row> + <row> + <value>10</value> + <value>test_txt</value> + <value>real_test.txt</value> + <value>0</value> + <value>txt</value> + <value>text/plain</value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/console/fixtures/txt.txt b/tests/console/fixtures/txt.txt new file mode 100644 index 0000000000..a78c858f5c --- /dev/null +++ b/tests/console/fixtures/txt.txt @@ -0,0 +1,2 @@ +<HTML>mime trigger</HTML> +The HTML tags should remain uppercase so that case-insensitivity can be checked. diff --git a/tests/console/thumbnail_test.php b/tests/console/thumbnail_test.php new file mode 100644 index 0000000000..45d7adacb9 --- /dev/null +++ b/tests/console/thumbnail_test.php @@ -0,0 +1,125 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_compatibility.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Tester\CommandTester; +use phpbb\console\command\thumbnail\generate; +use phpbb\console\command\thumbnail\delete; +use phpbb\console\command\thumbnail\recreate; + +class phpbb_console_command_thumbnail_test extends phpbb_database_test_case +{ + protected $db; + protected $config; + protected $cache; + protected $user; + protected $phpEx; + protected $phpbb_root_path; + protected $application; + + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/thumbnail.xml'); + } + + public function setUp() + { + global $config, $phpbb_root_path, $phpEx, $phpbb_filesystem; + + if (!@extension_loaded('gd')) + { + $this->markTestSkipped('Thumbnail tests require gd extension.'); + } + + parent::setUp(); + + $config = $this->config = new \phpbb\config\config(array( + 'img_min_thumb_filesize' => 2, + 'img_max_thumb_width' => 2, + 'img_imagick' => '', + )); + + $this->db = $this->db = $this->new_dbal(); + $this->user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime') + ); + $this->phpbb_root_path = $phpbb_root_path; + $this->phpEx = $phpEx; + + $this->cache = $this->getMock('\phpbb\cache\service', array(), array(new phpbb_mock_cache(), $this->config, $this->db, $this->phpbb_root_path, $this->phpEx)); + $this->cache->expects(self::any())->method('obtain_attach_extensions')->will(self::returnValue(array( + 'png' => array('display_cat' => ATTACHMENT_CATEGORY_IMAGE), + 'txt' => array('display_cat' => ATTACHMENT_CATEGORY_NONE), + ))); + + $this->application = new Application(); + $this->application->add(new generate($this->user, $this->db, $this->cache, $this->phpbb_root_path, $this->phpEx)); + $this->application->add(new delete($this->user, $this->db, $this->phpbb_root_path)); + $this->application->add(new recreate($this->user)); + + $phpbb_filesystem = new \phpbb\filesystem\filesystem(); + + copy(dirname(__FILE__) . '/fixtures/png.png', $this->phpbb_root_path . 'files/test_png_1'); + copy(dirname(__FILE__) . '/fixtures/png.png', $this->phpbb_root_path . 'files/test_png_2'); + copy(dirname(__FILE__) . '/fixtures/png.png', $this->phpbb_root_path . 'files/thumb_test_png_2'); + copy(dirname(__FILE__) . '/fixtures/txt.txt', $this->phpbb_root_path . 'files/test_txt'); + } + + protected function tearDown() + { + parent::tearDown(); + + unlink($this->phpbb_root_path . 'files/test_png_1'); + unlink($this->phpbb_root_path . 'files/test_png_2'); + unlink($this->phpbb_root_path . 'files/test_txt'); + unlink($this->phpbb_root_path . 'files/thumb_test_png_1'); + unlink($this->phpbb_root_path . 'files/thumb_test_png_2'); + } + + public function test_thumbnails() + { + $command_tester = $this->get_command_tester('thumbnail:generate'); + $exit_status = $command_tester->execute(array('command' => 'thumbnail:generate')); + + self::assertSame(true, file_exists($this->phpbb_root_path . 'files/thumb_test_png_1')); + self::assertSame(true, file_exists($this->phpbb_root_path . 'files/thumb_test_png_2')); + self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_txt')); + self::assertSame(0, $exit_status); + + $command_tester = $this->get_command_tester('thumbnail:delete'); + $exit_status = $command_tester->execute(array('command' => 'thumbnail:delete')); + + self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_png_1')); + self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_png_2')); + self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_txt')); + self::assertSame(0, $exit_status); + + $command_tester = $this->get_command_tester('thumbnail:recreate'); + $exit_status = $command_tester->execute(array('command' => 'thumbnail:recreate')); + + self::assertSame(true, file_exists($this->phpbb_root_path . 'files/thumb_test_png_1')); + self::assertSame(true, file_exists($this->phpbb_root_path . 'files/thumb_test_png_2')); + self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_txt')); + self::assertSame(0, $exit_status); + } + + public function get_command_tester($command_name) + { + $command = $this->application->find($command_name); + return new CommandTester($command); + } +} diff --git a/tests/content_visibility/delete_post_test.php b/tests/content_visibility/delete_post_test.php index 6ad6351a0c..ba0a21a1a4 100644 --- a/tests/content_visibility/delete_post_test.php +++ b/tests/content_visibility/delete_post_test.php @@ -292,12 +292,14 @@ class phpbb_content_visibility_delete_post_test extends phpbb_database_test_case { global $auth, $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $phpbb_root_path, $phpEx; - $config['search_type'] = 'phpbb_mock_search'; + $config = new \phpbb\config\config(array( + 'num_posts' => 3, + 'num_topics' => 1, + 'search_type' => 'phpbb_mock_search', + )); $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $phpbb_config = new \phpbb\config\config(array('num_posts' => 3, 'num_topics' => 1)); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - set_config_count(null, null, null, $phpbb_config); // Create auth mock $auth = $this->getMock('\phpbb\auth\auth'); @@ -307,13 +309,18 @@ class phpbb_content_visibility_delete_post_test extends phpbb_database_test_case ->will($this->returnValueMap(array( array('m_approve', 1, true), ))); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $attachment_delete = new \phpbb\attachment\delete($config, $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $phpbb_container = new phpbb_mock_container_builder(); $phpbb_container->set('notification_manager', new phpbb_mock_notification_manager()); - $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $phpbb_config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE)); + $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE)); + // Works as a workaround for tests + $phpbb_container->set('attachment.manager', $attachment_delete); delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $reason); diff --git a/tests/content_visibility/get_forums_visibility_sql_test.php b/tests/content_visibility/get_forums_visibility_sql_test.php index 28e463ecb5..6c5066119e 100644 --- a/tests/content_visibility/get_forums_visibility_sql_test.php +++ b/tests/content_visibility/get_forums_visibility_sql_test.php @@ -134,7 +134,9 @@ class phpbb_content_visibility_get_forums_visibility_sql_test extends phpbb_data ->method('acl_getf') ->with($this->stringContains('_'), $this->anything()) ->will($this->returnValueMap($permissions)); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $config = new phpbb\config\config(array()); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE); diff --git a/tests/content_visibility/get_global_visibility_sql_test.php b/tests/content_visibility/get_global_visibility_sql_test.php index 586bae8668..9ae4182673 100644 --- a/tests/content_visibility/get_global_visibility_sql_test.php +++ b/tests/content_visibility/get_global_visibility_sql_test.php @@ -134,7 +134,9 @@ class phpbb_content_visibility_get_global_visibility_sql_test extends phpbb_data ->method('acl_getf') ->with($this->stringContains('_'), $this->anything()) ->will($this->returnValueMap($permissions)); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $config = new phpbb\config\config(array()); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE); diff --git a/tests/content_visibility/get_visibility_sql_test.php b/tests/content_visibility/get_visibility_sql_test.php index 9ae2d2fdc4..aaaf64330e 100644 --- a/tests/content_visibility/get_visibility_sql_test.php +++ b/tests/content_visibility/get_visibility_sql_test.php @@ -81,7 +81,9 @@ class phpbb_content_visibility_get_visibility_sql_test extends phpbb_database_te ->method('acl_get') ->with($this->stringContains('_'), $this->anything()) ->will($this->returnValueMap($permissions)); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $config = new phpbb\config\config(array()); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE); diff --git a/tests/content_visibility/set_post_visibility_test.php b/tests/content_visibility/set_post_visibility_test.php index 36ebf58374..6375ce8f6d 100644 --- a/tests/content_visibility/set_post_visibility_test.php +++ b/tests/content_visibility/set_post_visibility_test.php @@ -124,7 +124,9 @@ class phpbb_content_visibility_set_post_visibility_test extends phpbb_database_t $cache = new phpbb_mock_cache; $db = $this->new_dbal(); $auth = $this->getMock('\phpbb\auth\auth'); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $config = new phpbb\config\config(array()); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE); @@ -175,7 +177,9 @@ class phpbb_content_visibility_set_post_visibility_test extends phpbb_database_t $cache = new phpbb_mock_cache; $db = $this->new_dbal(); $auth = $this->getMock('\phpbb\auth\auth'); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $config = new phpbb\config\config(array()); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE); diff --git a/tests/content_visibility/set_topic_visibility_test.php b/tests/content_visibility/set_topic_visibility_test.php index 6c34f42167..f4d65f9ce3 100644 --- a/tests/content_visibility/set_topic_visibility_test.php +++ b/tests/content_visibility/set_topic_visibility_test.php @@ -88,7 +88,9 @@ class phpbb_content_visibility_set_topic_visibility_test extends phpbb_database_ $cache = new phpbb_mock_cache; $db = $this->new_dbal(); $auth = $this->getMock('\phpbb\auth\auth'); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $config = new phpbb\config\config(array()); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE); diff --git a/tests/controller/common_helper_route.php b/tests/controller/common_helper_route.php index ff1af8119b..72c5328b0b 100644 --- a/tests/controller/common_helper_route.php +++ b/tests/controller/common_helper_route.php @@ -35,10 +35,6 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case ); $this->generate_route_objects(); $phpbb_dispatcher = new phpbb_mock_event_dispatcher; - $this->user = new \phpbb\user('\phpbb\datetime'); - - $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0')); - $this->template = new phpbb\template\twig\twig($this->phpbb_path_helper, $this->config, $this->user, new \phpbb\template\context()); } protected function get_phpbb_root_path() @@ -78,7 +74,7 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case $this->symfony_request = new \phpbb\symfony_request( $this->request ); - $this->filesystem = new \phpbb\filesystem(); + $this->filesystem = new \phpbb\filesystem\filesystem(); $this->phpbb_path_helper = new \phpbb\path_helper( $this->symfony_request, $this->filesystem, @@ -87,15 +83,51 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case $phpEx ); - $finder = new \phpbb\finder( - new \phpbb\filesystem(), + $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0')); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $this->user = new \phpbb\user($lang, '\phpbb\datetime');; + + $container = new phpbb_mock_container_builder(); + $container->setParameter('core.environment', PHPBB_ENVIRONMENT); + $cache_path = $phpbb_root_path . 'cache/twig'; + $context = new \phpbb\template\context(); + $loader = new \phpbb\template\twig\loader($this->filesystem, ''); + $twig = new \phpbb\template\twig\environment( + $this->config, + $this->filesystem, + $this->phpbb_path_helper, + $container, + $cache_path, + null, + $loader, + array( + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ) + ); + $this->template = new phpbb\template\twig\twig($this->phpbb_path_helper, $this->config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user))); + $container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig)); + + $this->extension_manager = new phpbb_mock_extension_manager( dirname(__FILE__) . '/', - new phpbb_mock_cache() + array( + 'vendor2/foo' => array( + 'ext_name' => 'vendor2/foo', + 'ext_active' => '1', + 'ext_path' => 'ext/vendor2/foo/', + ), + ) + ); + + $loader = new \Symfony\Component\Routing\Loader\YamlFileLoader( + new \phpbb\routing\file_locator($this->filesystem, dirname(__FILE__) . '/') ); - $finder->set_extensions(array_keys($this->extension_manager->all_enabled())); - $this->provider = new \phpbb\controller\provider(); - $this->provider->find_routing_files($finder); - $this->provider->find(dirname(__FILE__) . '/'); + $resources_locator = new \phpbb\routing\resources_locator\default_resources_locator(dirname(__FILE__) . '/', PHPBB_ENVIRONMENT, $this->extension_manager); + $this->router = new phpbb_mock_router($container, $resources_locator, $loader, dirname(__FILE__) . '/', 'php', PHPBB_ENVIRONMENT); + // Set correct current phpBB root path $this->root_path = $this->get_phpbb_root_path(); } @@ -127,6 +159,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case array('controller2', array(), true, false, '/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'), array('controller2', array(), false, false, '/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'), array('controller3', array('p' => 3), true, false, '/' . $this->path_to_app() . 'app.php/foo/bar/p-3', 'no params using empty array'), + + // Resolves DI parameters + array('controller4', array(), true, false, '/' . $this->path_to_app() . 'app.php/foo/' . PHPBB_ENVIRONMENT, 'di parameter'), ); } @@ -135,8 +170,10 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case */ public function test_helper_url_no_rewrite($route, $params, $is_amp, $session_id, $expected, $description) { - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/'); - $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id)); + $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0')); + $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper); + $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id), $description); } public function helper_url_data_with_rewrite() @@ -166,6 +203,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case array('controller2', array(), true, false, '/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'), array('controller2', array(), false, false, '/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'), array('controller3', array('p' => 3), true, false, '/' . $this->path_to_app() . 'foo/bar/p-3', 'no params using empty array'), + + // Resolves DI parameters + array('controller4', array(), true, false, '/' . $this->path_to_app() . 'foo/' . PHPBB_ENVIRONMENT, 'di parameter'), ); } @@ -175,8 +215,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case public function test_helper_url_with_rewrite($route, $params, $is_amp, $session_id, $expected, $description) { $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1')); - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/'); - $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id)); + $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper); + $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id), $description); } public function helper_url_data_absolute() @@ -206,6 +247,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case array('controller2', array(), true, false, 'http://localhost/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'), array('controller2', array(), false, false, 'http://localhost/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'), array('controller3', array('p' => 3), true, false, 'http://localhost/' . $this->path_to_app() . 'app.php/foo/bar/p-3', 'no params using empty array'), + + // Resolves DI parameters + array('controller4', array(), true, false, 'http://localhost/' . $this->path_to_app() . 'app.php/foo/' . PHPBB_ENVIRONMENT, 'di parameter'), ); } @@ -215,8 +259,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case public function test_helper_url_absolute($route, $params, $is_amp, $session_id, $expected, $description) { $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0')); - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/'); - $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::ABSOLUTE_URL)); + $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper); + $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::ABSOLUTE_URL), $description); } public function helper_url_data_relative_path() @@ -246,6 +291,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case array('controller2', array(), true, false, 'app.php/foo/bar', 'no params using empty array'), array('controller2', array(), false, false, 'app.php/foo/bar', 'no params using empty array'), array('controller3', array('p' => 3), true, false, 'app.php/foo/bar/p-3', 'no params using empty array'), + + // Resolves DI parameters + array('controller4', array(), true, false, 'app.php/foo/' . PHPBB_ENVIRONMENT, 'di parameter'), ); } @@ -255,8 +303,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case public function test_helper_url_relative_path($route, $params, $is_amp, $session_id, $expected, $description) { $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0')); - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/'); - $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::RELATIVE_PATH)); + $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper); + $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::RELATIVE_PATH), $description); } public function helper_url_data_network() @@ -286,6 +335,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case array('controller2', array(), true, false, '//localhost/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'), array('controller2', array(), false, false, '//localhost/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'), array('controller3', array('p' => 3), true, false, '//localhost/' . $this->path_to_app() . 'app.php/foo/bar/p-3', 'no params using empty array'), + + // Resolves DI parameters + array('controller4', array(), true, false, '//localhost/' . $this->path_to_app() . 'app.php/foo/' . PHPBB_ENVIRONMENT, 'di parameter'), ); } @@ -295,10 +347,11 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case public function test_helper_url_network($route, $params, $is_amp, $session_id, $expected, $description) { $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0')); - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/'); - $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::NETWORK_PATH)); + $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper); + $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::NETWORK_PATH), $description); } -//TODO + public function helper_url_data_absolute_with_rewrite() { return array( @@ -326,6 +379,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case array('controller2', array(), true, false, 'http://localhost/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'), array('controller2', array(), false, false, 'http://localhost/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'), array('controller3', array('p' => 3), true, false, 'http://localhost/' . $this->path_to_app() . 'foo/bar/p-3', 'no params using empty array'), + + // Resolves DI parameters + array('controller4', array(), true, false, 'http://localhost/' . $this->path_to_app() . 'foo/' . PHPBB_ENVIRONMENT, 'di parameter'), ); } @@ -335,8 +391,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case public function test_helper_url_absolute_with_rewrite($route, $params, $is_amp, $session_id, $expected, $description) { $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1')); - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/'); - $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::ABSOLUTE_URL)); + $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper); + $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::ABSOLUTE_URL), $description); } public function helper_url_data_relative_path_with_rewrite() @@ -375,8 +432,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case public function test_helper_url_relative_path_with_rewrite($route, $params, $is_amp, $session_id, $expected, $description) { $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1')); - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/'); - $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::RELATIVE_PATH)); + $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper); + $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::RELATIVE_PATH), $description); } public function helper_url_data_network_with_rewrite() @@ -406,6 +464,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case array('controller2', array(), true, false, '//localhost/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'), array('controller2', array(), false, false, '//localhost/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'), array('controller3', array('p' => 3), true, false, '//localhost/' . $this->path_to_app() . 'foo/bar/p-3', 'no params using empty array'), + + // Resolves DI parameters + array('controller4', array(), true, false, '//localhost/' . $this->path_to_app() . 'foo/' . PHPBB_ENVIRONMENT, 'di parameter'), ); } @@ -415,7 +476,8 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case public function test_helper_url_network_with_rewrite($route, $params, $is_amp, $session_id, $expected, $description) { $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1')); - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/'); - $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::NETWORK_PATH)); + $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper); + $this->assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::NETWORK_PATH), $description); } } diff --git a/tests/controller/config/routing.yml b/tests/controller/config/test/routing/environment.yml index 1e7df02684..1e7df02684 100644 --- a/tests/controller/config/routing.yml +++ b/tests/controller/config/test/routing/environment.yml diff --git a/tests/controller/controller_test.php b/tests/controller/controller_test.php index 62feee3fed..431b26b2bc 100644 --- a/tests/controller/controller_test.php +++ b/tests/controller/controller_test.php @@ -30,14 +30,25 @@ class phpbb_controller_controller_test extends phpbb_test_case 'ext_active' => '1', 'ext_path' => 'ext/vendor2/foo/', ), + 'vendor2/bar' => array( + 'ext_name' => 'vendor2/bar', + 'ext_active' => '1', + 'ext_path' => 'ext/vendor2/bar/', + ), )); } - public function test_provider() + public function test_router_default_loader() { - $provider = new \phpbb\controller\provider(); - $provider->find_routing_files($this->extension_manager->get_finder()); - $routes = $provider->find(__DIR__)->get_routes(); + $container = new phpbb_mock_container_builder(); + $container->setParameter('core.environment', PHPBB_ENVIRONMENT); + + $loader = new \Symfony\Component\Routing\Loader\YamlFileLoader( + new \phpbb\routing\file_locator(new \phpbb\filesystem\filesystem(), dirname(__FILE__) . '/') + ); + $resources_locator = new \phpbb\routing\resources_locator\default_resources_locator(dirname(__FILE__) . '/', PHPBB_ENVIRONMENT, $this->extension_manager); + $router = new phpbb_mock_router($container, $resources_locator, $loader, dirname(__FILE__) . '/', 'php', PHPBB_ENVIRONMENT); + $routes = $router->get_routes(); // This will need to be updated if any new routes are defined $this->assertInstanceOf('Symfony\Component\Routing\Route', $routes->get('core_controller')); @@ -49,6 +60,9 @@ class phpbb_controller_controller_test extends phpbb_test_case $this->assertInstanceOf('Symfony\Component\Routing\Route', $routes->get('controller2')); $this->assertEquals('/foo/bar', $routes->get('controller2')->getPath()); + $this->assertInstanceOf('Symfony\Component\Routing\Route', $routes->get('controller3')); + $this->assertEquals('/bar', $routes->get('controller3')->getPath()); + $this->assertNull($routes->get('controller_noroute')); } @@ -74,7 +88,7 @@ class phpbb_controller_controller_test extends phpbb_test_case include(__DIR__.'/phpbb/controller/foo.php'); } - $resolver = new \phpbb\controller\resolver(new \phpbb\user('\phpbb\datetime'), $container, dirname(__FILE__) . '/'); + $resolver = new \phpbb\controller\resolver($container, dirname(__FILE__) . '/'); $symfony_request = new Request(); $symfony_request->attributes->set('_controller', 'foo.controller:handle'); diff --git a/tests/controller/ext/vendor2/bar/config/services.yml b/tests/controller/ext/vendor2/bar/config/services.yml new file mode 100644 index 0000000000..05a8a1994d --- /dev/null +++ b/tests/controller/ext/vendor2/bar/config/services.yml @@ -0,0 +1,3 @@ +services: + bar.controller: + class: bar\controller diff --git a/tests/controller/ext/vendor2/bar/config/test/routing/environment.yml b/tests/controller/ext/vendor2/bar/config/test/routing/environment.yml new file mode 100644 index 0000000000..5696ecb180 --- /dev/null +++ b/tests/controller/ext/vendor2/bar/config/test/routing/environment.yml @@ -0,0 +1,3 @@ +controller3: + path: /bar + defaults: { _controller: bar.controller:handle } diff --git a/tests/controller/ext/vendor2/bar/controller.php b/tests/controller/ext/vendor2/bar/controller.php new file mode 100644 index 0000000000..ad35f5a051 --- /dev/null +++ b/tests/controller/ext/vendor2/bar/controller.php @@ -0,0 +1,18 @@ +<?php + +namespace bar; + +use Symfony\Component\HttpFoundation\Response; + +class controller +{ + /** + * Handle method + * + * @return null + */ + public function handle() + { + return new Response('Test', 200); + } +} diff --git a/tests/controller/ext/vendor2/foo/config/routing.yml b/tests/controller/ext/vendor2/foo/config/routing.yml index e3e8ee5f98..7d4ac7be93 100644 --- a/tests/controller/ext/vendor2/foo/config/routing.yml +++ b/tests/controller/ext/vendor2/foo/config/routing.yml @@ -5,3 +5,7 @@ controller1: include_controller2: resource: "routing_2.yml" prefix: /foo + +controller4: + path: /foo/%core.environment% + defaults: { _controller: foo.controller:handle } diff --git a/tests/datetime/from_format_test.php b/tests/datetime/from_format_test.php index 8968619bb5..7ecb546768 100644 --- a/tests/datetime/from_format_test.php +++ b/tests/datetime/from_format_test.php @@ -37,7 +37,11 @@ class phpbb_datetime_from_format_test extends phpbb_test_case */ public function test_from_format($timezone, $format, $expected) { - $user = new \phpbb\user('\phpbb\datetime'); + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->timezone = new DateTimeZone($timezone); $user->lang['datetime'] = array( 'TODAY' => 'Today', @@ -107,7 +111,11 @@ class phpbb_datetime_from_format_test extends phpbb_test_case */ public function test_relative_format_date($timestamp, $forcedate, $expected) { - $user = new \phpbb\user('\phpbb\datetime'); + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->timezone = new DateTimeZone('UTC'); $user->lang['datetime'] = array( 'TODAY' => 'Today', diff --git a/tests/dbal/auto_increment_test.php b/tests/dbal/auto_increment_test.php index 1ed8ea29e3..39eb6835ff 100644 --- a/tests/dbal/auto_increment_test.php +++ b/tests/dbal/auto_increment_test.php @@ -30,7 +30,8 @@ class phpbb_dbal_auto_increment_test extends phpbb_database_test_case parent::setUp(); $this->db = $this->new_dbal(); - $this->tools = new \phpbb\db\tools($this->db); + $factory = new \phpbb\db\tools\factory(); + $this->tools = $factory->get($this->db); $this->table_data = array( 'COLUMNS' => array( diff --git a/tests/dbal/boolean_processor_test.php b/tests/dbal/boolean_processor_test.php new file mode 100644 index 0000000000..226f5307b2 --- /dev/null +++ b/tests/dbal/boolean_processor_test.php @@ -0,0 +1,324 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php'; + +class phpbb_boolean_processor_test extends phpbb_database_test_case +{ + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/boolean_processor.xml'); + } + + public function test_single_not_like() + { + $db = $this->new_dbal(); + + $db->sql_return_on_error(true); + + $sql_ary = array( + 'SELECT' => 'u.user_id', + 'FROM' => array( + 'phpbb_users' => 'u', + ), + 'WHERE' => array('u.username_clean', 'NOT_LIKE', 'gr' . $db->get_any_char()), + 'ORDER_BY' => 'u.user_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); + $result = $db->sql_query($sql); + + $db->sql_return_on_error(false); + + $this->assertEquals(array( + array('user_id' => '1'), + array('user_id' => '2'), + array('user_id' => '3'), + array('user_id' => '6'), + ), $db->sql_fetchrowset($result), + ($result === false) ? + "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() : + var_export($sql, true) . ' ' . var_export($result, true) + ); + } + + public function test_single_like() + { + $db = $this->new_dbal(); + + $db->sql_return_on_error(true); + + $sql_ary = array( + 'SELECT' => 'u.user_id', + 'FROM' => array( + 'phpbb_users' => 'u', + ), + 'WHERE' => array('u.username_clean', 'LIKE', 'gr' . $db->get_any_char()), + 'ORDER_BY' => 'u.user_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); + $result = $db->sql_query($sql); + + $db->sql_return_on_error(false); + + $this->assertEquals(array( + array('user_id' => '4'), + array('user_id' => '5'), + ), $db->sql_fetchrowset($result), + ($result === false) ? + "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() : + var_export($sql, true) . ' ' . var_export($result, true) + ); + } + + public function test_single_not_in() + { + $db = $this->new_dbal(); + + $db->sql_return_on_error(true); + + $sql_ary = array( + 'SELECT' => 'u.user_id', + 'FROM' => array( + 'phpbb_users' => 'u', + ), + 'WHERE' => array('u.user_id', 'NOT_IN', array(3,4,5)), + 'ORDER_BY' => 'u.user_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); + $result = $db->sql_query($sql); + + $db->sql_return_on_error(false); + + $this->assertEquals(array( + array('user_id' => '1'), + array('user_id' => '2'), + array('user_id' => '6'), + ), $db->sql_fetchrowset($result), + ($result === false) ? + "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() : + var_export($sql, true) . ' ' . var_export($result, true) + ); + } + + public function test_single_in() + { + $db = $this->new_dbal(); + + $db->sql_return_on_error(true); + + $sql_ary = array( + 'SELECT' => 'u.user_id', + 'FROM' => array( + 'phpbb_users' => 'u', + ), + 'WHERE' => array('u.user_id', 'IN', array(3,4,5)), + 'ORDER_BY' => 'u.user_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); + $result = $db->sql_query($sql); + + $db->sql_return_on_error(false); + + $this->assertEquals(array( + array('user_id' => '3'), + array('user_id' => '4'), + array('user_id' => '5'), + ), $db->sql_fetchrowset($result), + ($result === false) ? + "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() : + var_export($sql, true) . ' ' . var_export($result, true) + ); + } + + public function test_and_of_or_of_and() + { + $db = $this->new_dbal(); + + $db->sql_return_on_error(true); + + $sql_ary = array( + 'SELECT' => 'u.user_id', + 'FROM' => array( + 'phpbb_users' => 'u', + 'phpbb_user_group' => 'ug', + ), + 'LEFT_JOIN' => array( + array( + 'FROM' => array( + 'phpbb_banlist' => 'b', + ), + 'ON' => 'u.user_id = b.ban_userid', + ), + ), + 'WHERE' => array('AND', + array( + array('OR', + array( + array('AND', + array( + array('ug.user_id', 'IN', array(1, 2, 3, 4)), + array('ug.group_id', '=', 2), + ), + ), + array('AND', + array( + array('ug.group_id', '=', 1), + array('b.ban_id', 'IS_NOT', NULL), + ), + ), + ), + ), + array('u.user_id', '=', 'ug.user_id'), + ), + ), + 'ORDER_BY' => 'u.user_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); + $result = $db->sql_query($sql); + + $db->sql_return_on_error(false); + + $this->assertEquals(array( + array('user_id' => '2'), + array('user_id' => '4'), + ), $db->sql_fetchrowset($result), + ($result === false) ? + "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() : + var_export($sql, true) . ' ' . var_export($result, true) + ); + } + + public function test_triple_and_with_in() + { + $db = $this->new_dbal(); + + $db->sql_return_on_error(true); + + $sql_ary = array( + 'SELECT' => 'u.user_id', + 'FROM' => array( + 'phpbb_users' => 'u', + 'phpbb_user_group' => 'ug', + ), + 'WHERE' => array('AND', + array( + array('ug.user_id', 'IN', array(1, 2, 3, 4)), + array('ug.group_id', '=', 1), + array('u.user_id', '=', 'ug.user_id'), + ), + ), + 'ORDER_BY' => 'u.user_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); + $result = $db->sql_query($sql); + + $db->sql_return_on_error(false); + + $this->assertEquals(array( + array('user_id' => '1'), + array('user_id' => '2'), + array('user_id' => '3'), + ), $db->sql_fetchrowset($result), + ($result === false) ? + "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() : + var_export($sql, true) . ' ' . var_export($result, true) + ); + + } + + public function test_double_and_with_not_of_or() + { + $db = $this->new_dbal(); + + $db->sql_return_on_error(true); + + $sql_ary = array( + 'SELECT' => 'u.user_id', + 'FROM' => array( + 'phpbb_users' => 'u', + 'phpbb_user_group' => 'ug', + ), + 'WHERE' => array('AND', + array( + array('NOT', + array( + array('OR', + array( + array('ug.group_id', '=', 1), + array('ug.group_id', '=', 2), + ), + ), + ), + ), + array('u.user_id', '=', 'ug.user_id'), + ), + ), + 'ORDER_BY' => 'u.user_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); + $result = $db->sql_query($sql); + + $db->sql_return_on_error(false); + + $this->assertEquals(array(), $db->sql_fetchrowset($result), + ($result === false) ? + "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() : + var_export($sql, true) . ' ' . var_export($result, true) + ); + } + + public function test_triple_and_with_is_null() + { + $db = $this->new_dbal(); + + $db->sql_return_on_error(true); + + $sql_ary = array( + 'SELECT' => 'u.username', + 'FROM' => array( + 'phpbb_users' => 'u', + 'phpbb_user_group' => 'ug', + ), + 'LEFT_JOIN' => array( + array( + 'FROM' => array( + 'phpbb_banlist' => 'b', + ), + 'ON' => 'u.user_id = b.ban_userid', + ), + ), + 'WHERE' => array('AND', + array( + array('ug.group_id', '=', 1), + array('u.user_id', '=', 'ug.user_id'), + array('b.ban_id', 'IS', NULL), + ), + ), + 'ORDER_BY' => 'u.username', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); + $result = $db->sql_query($sql); + + $db->sql_return_on_error(false); + + $this->assertEquals(array( + array('username' => 'helper'), + array('username' => 'mass email'), + ), $db->sql_fetchrowset($result), + ($result === false) ? + "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() : + var_export($sql, true) . ' ' . var_export($result, true) + ); + } +} diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php index 1ae34bd2b6..edf57189cb 100644 --- a/tests/dbal/connect_test.php +++ b/tests/dbal/connect_test.php @@ -22,7 +22,9 @@ class phpbb_dbal_connect_test extends phpbb_database_test_case public function test_failing_connect() { - global $phpbb_root_path, $phpEx; + global $phpbb_root_path, $phpEx, $phpbb_filesystem; + + $phpbb_filesystem = new phpbb\filesystem\filesystem(); $config = $this->get_database_config(); diff --git a/tests/dbal/db_tools_test.php b/tests/dbal/db_tools_test.php index 5832b966d8..aa0b6ccf48 100644 --- a/tests/dbal/db_tools_test.php +++ b/tests/dbal/db_tools_test.php @@ -17,7 +17,7 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case { /** @var \phpbb\db\driver\driver_interface */ protected $db; - /** @var \phpbb\db\tools */ + /** @var \phpbb\db\tools\tools_interface */ protected $tools; protected $table_exists; protected $table_data; @@ -32,7 +32,8 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case parent::setUp(); $this->db = $this->new_dbal(); - $this->tools = new \phpbb\db\tools($this->db); + $factory = new \phpbb\db\tools\factory(); + $this->tools = $factory->get($this->db); $this->table_data = array( 'COLUMNS' => array( @@ -340,7 +341,7 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case public function test_perform_schema_changes_drop_tables() { - $db_tools = $this->getMock('\phpbb\db\tools', array( + $db_tools = $this->getMock('\phpbb\db\tools\tools', array( 'sql_table_exists', 'sql_table_drop', ), array(&$this->db)); @@ -366,7 +367,7 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case public function test_perform_schema_changes_drop_columns() { - $db_tools = $this->getMock('\phpbb\db\tools', array( + $db_tools = $this->getMock('\phpbb\db\tools\tools', array( 'sql_column_exists', 'sql_column_remove', ), array(&$this->db)); diff --git a/tests/dbal/fixtures/boolean_processor.xml b/tests/dbal/fixtures/boolean_processor.xml new file mode 100644 index 0000000000..c5da677116 --- /dev/null +++ b/tests/dbal/fixtures/boolean_processor.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_banlist"> + <column>ban_id</column> + <column>ban_userid</column> + <row> + <value>1</value> + <value>2</value> + </row> + </table> + <table name="phpbb_users"> + <column>user_id</column> + <column>username</column> + <column>username_clean</column> + <column>user_permissions</column> + <column>user_sig</column> + <row> + <value>1</value> + <value>mass email</value> + <value>mass email</value> + <value></value> + <value></value> + </row> + <row> + <value>2</value> + <value>banned</value> + <value>banned</value> + <value></value> + <value></value> + </row> + <row> + <value>3</value> + <value>helper</value> + <value>helper</value> + <value></value> + <value></value> + </row> + <row> + <value>4</value> + <value>GroupBPal</value> + <value>groupbpal</value> + <value></value> + <value></value> + </row> + <row> + <value>5</value> + <value>GroupBPal2</value> + <value>groupBPal2</value> + <value></value> + <value></value> + </row> + <row> + <value>6</value> + <value>not in group</value> + <value>not in group</value> + <value></value> + <value></value> + </row> + </table> + <table name="phpbb_user_group"> + <column>user_id</column> + <column>group_id</column> + <row> + <value>1</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>1</value> + </row> + <row> + <value>3</value> + <value>1</value> + </row> + <row> + <value>4</value> + <value>2</value> + </row> + <row> + <value>5</value> + <value>2</value> + </row> + </table> +</dataset> diff --git a/tests/dbal/migrator_test.php b/tests/dbal/migrator_test.php index 4c4306888c..f52e6ea63d 100644 --- a/tests/dbal/migrator_test.php +++ b/tests/dbal/migrator_test.php @@ -38,7 +38,8 @@ class phpbb_dbal_migrator_test extends phpbb_database_test_case parent::setUp(); $this->db = $this->new_dbal(); - $this->db_tools = new \phpbb\db\tools($this->db); + $factory = new \phpbb\db\tools\factory(); + $this->db_tools = $factory->get($this->db); $this->config = new \phpbb\config\db($this->db, new phpbb_mock_cache, 'phpbb_config'); @@ -62,14 +63,12 @@ class phpbb_dbal_migrator_test extends phpbb_database_test_case ); $container->set('migrator', $this->migrator); $container->set('dispatcher', new phpbb_mock_event_dispatcher()); - $user = new \phpbb\user('\phpbb\datetime'); $this->extension_manager = new \phpbb\extension\manager( $container, $this->db, $this->config, - new phpbb\filesystem(), - $user, + new phpbb\filesystem\filesystem(), 'phpbb_ext', dirname(__FILE__) . '/../../phpBB/', 'php', diff --git a/tests/dbal/migrator_tool_module_test.php b/tests/dbal/migrator_tool_module_test.php index 08c3e979b8..a71334f23f 100644 --- a/tests/dbal/migrator_tool_module_test.php +++ b/tests/dbal/migrator_tool_module_test.php @@ -27,19 +27,24 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case parent::setup(); - // Force add_log function to not be used + // Disable the logs $skip_add_log = true; $db = $this->db = $this->new_dbal(); - $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\null(), new \phpbb\config\config(array()), $this->db, $phpbb_root_path, $phpEx); - $user = $this->user = new \phpbb\user('\phpbb\user'); + $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\dummy(), new \phpbb\config\config(array()), $this->db, $phpbb_root_path, $phpEx); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = $this->user = new \phpbb\user($lang, '\phpbb\datetime'); $cache = new phpbb_mock_cache; $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $auth = $this->getMock('\phpbb\auth\auth'); $phpbb_log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE); - $this->tool = new \phpbb\db\migration\tool\module($this->db, $this->cache, $this->user, $phpbb_root_path, $phpEx, 'phpbb_modules'); + $phpbb_extension_manager = new phpbb_mock_extension_manager($phpbb_root_path); + $module_manager = new \phpbb\module\module_manager($cache, $this->db, $phpbb_extension_manager, MODULES_TABLE, $phpbb_root_path, $phpEx); + + $this->tool = new \phpbb\db\migration\tool\module($this->db, $this->cache, $this->user, $module_manager, $phpbb_root_path, $phpEx, 'phpbb_modules'); } public function exists_data() diff --git a/tests/dbal/migrator_tool_permission_test.php b/tests/dbal/migrator_tool_permission_test.php index 2d673864f7..bfb2e07080 100644 --- a/tests/dbal/migrator_tool_permission_test.php +++ b/tests/dbal/migrator_tool_permission_test.php @@ -34,7 +34,7 @@ class phpbb_dbal_migrator_tool_permission_test extends phpbb_database_test_case parent::setup(); $db = $this->db = $this->new_dbal(); - $cache = $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\null(), new \phpbb\config\config(array()), $this->db, $phpbb_root_path, $phpEx); + $cache = $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\dummy(), new \phpbb\config\config(array()), $this->db, $phpbb_root_path, $phpEx); $this->auth = new \phpbb\auth\auth(); $this->tool = new \phpbb\db\migration\tool\permission($this->db, $this->cache, $this->auth, $phpbb_root_path, $phpEx); diff --git a/tests/di/create_container_test.php b/tests/di/create_container_test.php index 4ae6017989..2d94f1d778 100644 --- a/tests/di/create_container_test.php +++ b/tests/di/create_container_test.php @@ -14,6 +14,7 @@ namespace { require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + require_once dirname(__FILE__) . '/fixtures/ext/vendor/enabled_4/di/extension.php'; class phpbb_di_container_test extends \phpbb_test_case { @@ -30,7 +31,8 @@ namespace { $this->phpbb_root_path = dirname(__FILE__) . '/'; $this->config_php = new \phpbb\config_php_file($this->phpbb_root_path . 'fixtures/', 'php'); - $this->builder = new phpbb_mock_phpbb_di_container_builder($this->config_php, $this->phpbb_root_path . 'fixtures/', 'php'); + $this->builder = new phpbb_mock_phpbb_di_container_builder($this->phpbb_root_path . 'fixtures/', 'php'); + $this->builder->with_config($this->config_php); $this->filename = $this->phpbb_root_path . '../tmp/container.php'; if (is_file($this->filename)) @@ -57,6 +59,9 @@ namespace // Checks use_extensions $this->assertTrue($container->hasParameter('enabled')); + $this->assertTrue($container->hasParameter('enabled_2')); + $this->assertTrue($container->hasParameter('enabled_3')); + $this->assertTrue($container->hasParameter('enabled_4')); $this->assertFalse($container->hasParameter('disabled')); $this->assertFalse($container->hasParameter('available')); @@ -74,9 +79,9 @@ namespace $this->assertTrue($container->isFrozen()); } - public function test_dump_container() + public function test_without_cache() { - $this->builder->set_dump_container(false); + $this->builder->without_cache(); $container = $this->builder->get_container(); $this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container); @@ -90,9 +95,9 @@ namespace $this->assertTrue($container->isFrozen()); } - public function test_use_extensions() + public function test_without_extensions() { - $this->builder->set_use_extensions(false); + $this->builder->without_extensions(); $container = $this->builder->get_container(); $this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container); @@ -105,9 +110,9 @@ namespace $this->assertFalse($container->hasParameter('available')); } - public function test_compile_container() + public function test_without_compiled_container() { - $this->builder->set_compile_container(false); + $this->builder->without_compiled_container(); $container = $this->builder->get_container(); $this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container); @@ -115,19 +120,9 @@ namespace $this->assertFalse($container->isFrozen()); } - public function test_inject_config() + public function test_with_config_path() { - $this->builder->set_inject_config(false); - $container = $this->builder->get_container(); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container); - - // Checks inject_config - $this->assertFalse($container->hasParameter('dbal.dbhost')); - } - - public function test_set_config_path() - { - $this->builder->set_config_path($this->phpbb_root_path . 'fixtures/other_config/'); + $this->builder->with_config_path($this->phpbb_root_path . 'fixtures/other_config/'); $container = $this->builder->get_container(); $this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container); @@ -135,70 +130,32 @@ namespace $this->assertFalse($container->hasParameter('core')); } - public function test_set_custom_parameters() + public function test_with_custom_parameters() { - $this->builder->set_custom_parameters(array('my_parameter' => true)); + $this->builder->with_custom_parameters(array('my_parameter' => true)); $container = $this->builder->get_container(); $this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container); $this->assertTrue($container->hasParameter('my_parameter')); - $this->assertFalse($container->hasParameter('core.root_path')); } } } -namespace phpbb\db\driver +namespace phpbb\extension { - class container_mock extends \phpbb\db\driver\driver + class manager_mock extends \phpbb\extension\manager { - public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - } - - public function sql_query($query = '', $cache_ttl = 0) - { - } - - public function sql_fetchrow($query_id = false) - { - } - - public function sql_freeresult($query_id = false) - { - } - - function sql_server_info($raw = false, $use_cache = true) - { - } - - function sql_affectedrows() - { - } - - function sql_rowseek($rownum, &$query_id) - { - } - - function sql_nextid() - { - } - - function sql_escape($msg) - { - } - - function sql_like_expression($expression) - { - } - - function sql_not_like_expression($expression) + public function __construct() { } - function sql_fetchrowset($query_id = false) + public function all_enabled($phpbb_relative = true) { return array( - array('ext_name' => 'vendor/enabled'), + 'vendor/enabled' => dirname(__FILE__) . '/fixtures/ext/vendor/enabled/', + 'vendor/enabled-2' => dirname(__FILE__) . '/fixtures/ext/vendor/enabled-2/', + 'vendor/enabled-3' => dirname(__FILE__) . '/fixtures/ext/vendor/enabled-3/', + 'vendor/enabled_4' => dirname(__FILE__) . '/fixtures/ext/vendor/enabled_4/', ); } } diff --git a/tests/di/fixtures/config.php b/tests/di/fixtures/config.php index 04e20f63d8..1e9207d924 100644 --- a/tests/di/fixtures/config.php +++ b/tests/di/fixtures/config.php @@ -1,11 +1,11 @@ <?php // phpBB 3.1.x auto-generated configuration file // Do not change anything in this file! -$dbms = 'container_mock'; +$dbms = 'mysql'; $dbhost = '127.0.0.1'; $dbport = ''; $dbname = 'phpbb'; $dbuser = 'root'; $dbpasswd = ''; $table_prefix = 'phpbb_'; -$acm_type = '\phpbb\cache\driver\null'; +$acm_type = '\phpbb\cache\driver\dummy'; diff --git a/tests/di/fixtures/config/production/config.yml b/tests/di/fixtures/config/production/config.yml new file mode 100644 index 0000000000..fcfa84f68b --- /dev/null +++ b/tests/di/fixtures/config/production/config.yml @@ -0,0 +1,2 @@ +core: + require_dev_dependencies: true diff --git a/tests/di/fixtures/config/production/container/environment.yml b/tests/di/fixtures/config/production/container/environment.yml new file mode 100644 index 0000000000..9dcf11d865 --- /dev/null +++ b/tests/di/fixtures/config/production/container/environment.yml @@ -0,0 +1,29 @@ +parameters: + core: true + +services: + config.php: + synthetic: true + + dbal.conn: + class: phpbb\db\driver\factory + arguments: + - @service_container + + dispatcher: + class: phpbb\db\driver\container_mock + + ext.manager: + class: phpbb\extension\manager_mock + + template.twig.environment: + class: Exception + arguments: + - ~ + - ~ + - ~ + - ~ + - ~ + - ~ + - ~ + - [] diff --git a/tests/di/fixtures/config/test/config.yml b/tests/di/fixtures/config/test/config.yml new file mode 100644 index 0000000000..fcfa84f68b --- /dev/null +++ b/tests/di/fixtures/config/test/config.yml @@ -0,0 +1,2 @@ +core: + require_dev_dependencies: true diff --git a/tests/di/fixtures/config/services.yml b/tests/di/fixtures/config/test/container/environment.yml index f2a22ae109..14c986d123 100644 --- a/tests/di/fixtures/config/services.yml +++ b/tests/di/fixtures/config/test/container/environment.yml @@ -12,3 +12,15 @@ services: dispatcher: class: phpbb\db\driver\container_mock + + template.twig.environment: + class: Exception + arguments: + - ~ + - ~ + - ~ + - ~ + - ~ + - ~ + - ~ + - [] diff --git a/tests/di/fixtures/ext/vendor/disabled/config/services.yml b/tests/di/fixtures/ext/vendor/disabled/config/test/container/environment.yml index 31ada384bf..31ada384bf 100644 --- a/tests/di/fixtures/ext/vendor/disabled/config/services.yml +++ b/tests/di/fixtures/ext/vendor/disabled/config/test/container/environment.yml diff --git a/tests/di/fixtures/ext/vendor/enabled-2/config/test/container/environment.yml b/tests/di/fixtures/ext/vendor/enabled-2/config/test/container/environment.yml new file mode 100644 index 0000000000..feeb5a7a2d --- /dev/null +++ b/tests/di/fixtures/ext/vendor/enabled-2/config/test/container/environment.yml @@ -0,0 +1,2 @@ +parameters: + enabled_2: true diff --git a/tests/di/fixtures/ext/vendor/enabled-3/config/services.yml b/tests/di/fixtures/ext/vendor/enabled-3/config/services.yml new file mode 100644 index 0000000000..0dae35d2bd --- /dev/null +++ b/tests/di/fixtures/ext/vendor/enabled-3/config/services.yml @@ -0,0 +1,2 @@ +parameters: + enabled_3: true diff --git a/tests/di/fixtures/ext/vendor/enabled/config/services.yml b/tests/di/fixtures/ext/vendor/enabled/config/default/container/environment.yml index 88a7919ed1..88a7919ed1 100644 --- a/tests/di/fixtures/ext/vendor/enabled/config/services.yml +++ b/tests/di/fixtures/ext/vendor/enabled/config/default/container/environment.yml diff --git a/tests/di/fixtures/ext/vendor/enabled_4/di/extension.php b/tests/di/fixtures/ext/vendor/enabled_4/di/extension.php new file mode 100644 index 0000000000..8e5ed6c52c --- /dev/null +++ b/tests/di/fixtures/ext/vendor/enabled_4/di/extension.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace vendor\enabled_4\di; + +use phpbb\extension\di\extension_base; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; + +/** +* Container core extension +*/ +class extension extends extension_base +{ + protected function load_services(ContainerBuilder $container) + { + $filesystem = new \phpbb\filesystem\filesystem(); + $loader = new YamlFileLoader($container, new FileLocator($filesystem->realpath($this->ext_path))); + $loader->load('environment.yml'); + } +} diff --git a/tests/di/fixtures/ext/vendor/enabled_4/environment.yml b/tests/di/fixtures/ext/vendor/enabled_4/environment.yml new file mode 100644 index 0000000000..d0affe4fd6 --- /dev/null +++ b/tests/di/fixtures/ext/vendor/enabled_4/environment.yml @@ -0,0 +1,2 @@ +parameters: + enabled_4: true diff --git a/tests/di/fixtures/other_config/production/config.yml b/tests/di/fixtures/other_config/production/config.yml new file mode 100644 index 0000000000..fcfa84f68b --- /dev/null +++ b/tests/di/fixtures/other_config/production/config.yml @@ -0,0 +1,2 @@ +core: + require_dev_dependencies: true diff --git a/tests/di/fixtures/other_config/production/container/environment.yml b/tests/di/fixtures/other_config/production/container/environment.yml new file mode 100644 index 0000000000..4960562a6c --- /dev/null +++ b/tests/di/fixtures/other_config/production/container/environment.yml @@ -0,0 +1,29 @@ +parameters: + other_config: true + +services: + config.php: + synthetic: true + + dbal.conn: + class: phpbb\db\driver\factory + arguments: + - @service_container + + dispatcher: + class: phpbb\db\driver\container_mock + + ext.manager: + class: phpbb\extension\manager_mock + + template.twig.environment: + class: Exception + arguments: + - ~ + - ~ + - ~ + - ~ + - ~ + - ~ + - ~ + - [] diff --git a/tests/di/fixtures/other_config/test/config.yml b/tests/di/fixtures/other_config/test/config.yml new file mode 100644 index 0000000000..fcfa84f68b --- /dev/null +++ b/tests/di/fixtures/other_config/test/config.yml @@ -0,0 +1,2 @@ +core: + require_dev_dependencies: true diff --git a/tests/di/fixtures/other_config/services.yml b/tests/di/fixtures/other_config/test/container/environment.yml index c299bfc648..e285b1b781 100644 --- a/tests/di/fixtures/other_config/services.yml +++ b/tests/di/fixtures/other_config/test/container/environment.yml @@ -12,3 +12,15 @@ services: dispatcher: class: phpbb\db\driver\container_mock + + template.twig.environment: + class: Exception + arguments: + - ~ + - ~ + - ~ + - ~ + - ~ + - ~ + - ~ + - [] diff --git a/tests/di/ordered_service_collection_test.php b/tests/di/ordered_service_collection_test.php new file mode 100644 index 0000000000..47e6d23744 --- /dev/null +++ b/tests/di/ordered_service_collection_test.php @@ -0,0 +1,51 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_ordered_service_collection_test extends \phpbb_test_case +{ + /** + * @var \phpbb\di\ordered_service_collection + */ + protected $service_collection; + + public function setUp() + { + $container = new phpbb_mock_container_builder(); + $container->set('foo', new StdClass); + $container->set('bar', new StdClass); + $container->set('foobar', new StdClass); + $container->set('barfoo', new StdClass); + + $this->service_collection = new \phpbb\di\ordered_service_collection($container); + $this->service_collection->add('foo', 7); + $this->service_collection->add('bar', 3); + $this->service_collection->add('barfoo', 5); + $this->service_collection->add('foobar', 2); + + parent::setUp(); + } + + public function test_service_collection() + { + $service_names = array(); + + // Test the iterator + foreach ($this->service_collection as $name => $service) + { + $service_names[] = $name; + $this->assertInstanceOf('StdClass', $service); + } + + $this->assertSame(array('foobar', 'bar', 'barfoo', 'foo'), $service_names); + } +} diff --git a/tests/di/service_collection_test.php b/tests/di/service_collection_test.php new file mode 100644 index 0000000000..5b51254a4a --- /dev/null +++ b/tests/di/service_collection_test.php @@ -0,0 +1,47 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_service_collection_test extends \phpbb_test_case +{ + /** + * @var \phpbb\di\service_collection + */ + protected $service_collection; + + public function setUp() + { + $container = new phpbb_mock_container_builder(); + $container->set('foo', new StdClass); + $container->set('bar', new StdClass); + + $this->service_collection = new \phpbb\di\service_collection($container); + $this->service_collection->add('foo'); + $this->service_collection->add('bar'); + + parent::setUp(); + } + + public function test_service_collection() + { + $service_names = array(); + + // Test the iterator + foreach ($this->service_collection as $name => $service) + { + $service_names[] = $name; + $this->assertInstanceOf('StdClass', $service); + } + + $this->assertSame(array('foo', 'bar'), $service_names); + } +} diff --git a/tests/error_collector_test.php b/tests/error_collector_test.php index b92c4fa6bb..ddbe2e3af1 100644 --- a/tests/error_collector_test.php +++ b/tests/error_collector_test.php @@ -15,6 +15,15 @@ require_once dirname(__FILE__) . '/../phpBB/includes/functions.php'; class phpbb_error_collector_test extends phpbb_test_case { + public function setUp() + { + parent::setUp(); + + global $phpbb_filesystem; + + $phpbb_filesystem = new \phpbb\filesystem\filesystem(); + } + public function test_collection() { $collector = new \phpbb\error_collector(E_ALL | E_STRICT); // php set_error_handler() default diff --git a/tests/event/exception_listener_test.php b/tests/event/exception_listener_test.php index 4d3453cd83..e643fadf2c 100644 --- a/tests/event/exception_listener_test.php +++ b/tests/event/exception_listener_test.php @@ -79,10 +79,12 @@ class exception_listener extends phpbb_test_case ->disableOriginalConstructor() ->getMock(); - $user = new \phpbb\user('\phpbb\datetime'); - $user->add_lang('common'); + global $phpbb_root_path, $phpEx; - $exception_listener = new \phpbb\event\kernel_exception_subscriber($template, $user); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + + $exception_listener = new \phpbb\event\kernel_exception_subscriber($template, $lang); $event = new \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent($this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'), $request, \Symfony\Component\HttpKernel\HttpKernelInterface::MASTER_REQUEST, $exception); $exception_listener->on_kernel_exception($event); diff --git a/tests/event/md_exporter_test.php b/tests/event/md_exporter_test.php index 1a51204cbe..a6c1dc78de 100644 --- a/tests/event/md_exporter_test.php +++ b/tests/event/md_exporter_test.php @@ -23,7 +23,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case 'event' => 'acp_bbcodes_actions_append', 'files' => array( 'prosilver' => array(), - 'subsilver2' => array(), 'adm' => array('acp_bbcodes.html'), ), 'since' => '3.1.0-a3', @@ -36,7 +35,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case 'event' => 'acp_bbcodes_actions_prepend', 'files' => array( 'prosilver' => array(), - 'subsilver2' => array(), 'adm' => array('acp_bbcodes.html'), ), 'since' => '3.1.0-a5', @@ -47,7 +45,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case 'event' => 'acp_bbcodes_actions_prepend2', 'files' => array( 'prosilver' => array(), - 'subsilver2' => array(), 'adm' => array('acp_bbcodes.html'), ), 'since' => '3.1.0-a4', @@ -63,7 +60,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case 'event' => 'acp_bbcodes_actions_prepend', 'files' => array( 'prosilver' => array(), - 'subsilver2' => array(), 'adm' => array('acp_bbcodes.html'), ), 'since' => '3.1.0-a5', @@ -74,7 +70,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case 'event' => 'acp_bbcodes_actions_prepend2', 'files' => array( 'prosilver' => array(), - 'subsilver2' => array(), 'adm' => array('acp_bbcodes.html'), ), 'since' => '3.1.0-a4', @@ -130,7 +125,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case $styles = array( 'adm/style/' => 'adm', 'styles/prosilver/template/' => 'styles', - 'styles/subsilver2/template/' => 'styles', ); foreach ($styles as $path => $filter) { diff --git a/tests/extension/ext/vendor2/bar/acp/a_info.php b/tests/extension/ext/vendor2/bar/acp/a_info.php index 8132df587f..8268006f9f 100644 --- a/tests/extension/ext/vendor2/bar/acp/a_info.php +++ b/tests/extension/ext/vendor2/bar/acp/a_info.php @@ -9,7 +9,6 @@ class a_info return array( 'filename' => 'vendor2\\bar\\acp\\a_module', 'title' => 'Bar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('ACP_MODS')), ), diff --git a/tests/extension/ext/vendor2/bar/migrations/bar.php b/tests/extension/ext/vendor2/bar/migrations/bar.php new file mode 100644 index 0000000000..ea5ddb6b8b --- /dev/null +++ b/tests/extension/ext/vendor2/bar/migrations/bar.php @@ -0,0 +1,7 @@ +<?php + +namespace vendor2\foo\migrations; + +class bar +{ +} diff --git a/tests/extension/ext/vendor2/bar/migrations/foo.php b/tests/extension/ext/vendor2/bar/migrations/foo.php new file mode 100644 index 0000000000..d727c2f954 --- /dev/null +++ b/tests/extension/ext/vendor2/bar/migrations/foo.php @@ -0,0 +1,54 @@ +<?php + +namespace vendor2\foo\migrations; + +class foo implements \phpbb\db\migration\migration_interface +{ + /** + * {@inheritdoc} + */ + static public function depends_on() + { + return array(); + } + + /** + * {@inheritdoc} + */ + public function effectively_installed() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function update_schema() + { + return array(); + } + + /** + * {@inheritdoc} + */ + public function revert_schema() + { + return array(); + } + + /** + * {@inheritdoc} + */ + public function update_data() + { + return array(); + } + + /** + * {@inheritdoc} + */ + public function revert_data() + { + return array(); + } +} diff --git a/tests/extension/ext/vendor2/foo/acp/a_info.php b/tests/extension/ext/vendor2/foo/acp/a_info.php index e1eaa340b7..48ab4cf8e7 100644 --- a/tests/extension/ext/vendor2/foo/acp/a_info.php +++ b/tests/extension/ext/vendor2/foo/acp/a_info.php @@ -9,7 +9,6 @@ class a_info return array( 'filename' => 'vendor2\\foo\\acp\\a_module', 'title' => 'Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => 'ext_vendor2/foo', 'cat' => array('ACP_MODS')), ), diff --git a/tests/extension/ext/vendor2/foo/acp/fail_info.php b/tests/extension/ext/vendor2/foo/acp/fail_info.php index d9b4353957..78479fee70 100644 --- a/tests/extension/ext/vendor2/foo/acp/fail_info.php +++ b/tests/extension/ext/vendor2/foo/acp/fail_info.php @@ -13,7 +13,6 @@ class foo_info return array( 'filename' => 'vendor2\foo\acp\fail_module', 'title' => 'Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('ACP_MODS')), ), diff --git a/tests/extension/ext/vendor2/foo/mcp/a_info.php b/tests/extension/ext/vendor2/foo/mcp/a_info.php index b5599fde65..2532e44b12 100644 --- a/tests/extension/ext/vendor2/foo/mcp/a_info.php +++ b/tests/extension/ext/vendor2/foo/mcp/a_info.php @@ -9,7 +9,6 @@ class a_info return array( 'filename' => 'vendor2\\foo\\mcp\\a_module', 'title' => 'Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('MCP_MAIN')), ), diff --git a/tests/extension/extension_base_test.php b/tests/extension/extension_base_test.php index eee38186db..775a23e198 100644 --- a/tests/extension/extension_base_test.php +++ b/tests/extension/extension_base_test.php @@ -11,6 +11,9 @@ * */ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/ext/vendor2/bar/migrations/bar.php'; +require_once dirname(__FILE__) . '/ext/vendor2/bar/migrations/foo.php'; +require_once dirname(__FILE__) . '/ext/vendor2/bar/migrations/migration.php'; class phpbb_extension_extension_base_test extends phpbb_test_case { @@ -61,9 +64,7 @@ class phpbb_extension_extension_base_test extends phpbb_test_case return array( array( 'vendor2/bar', - array( - '\vendor2\bar\migrations\migration', - ), + array('\vendor2\bar\migrations\migration'), ), ); } @@ -74,6 +75,8 @@ class phpbb_extension_extension_base_test extends phpbb_test_case public function test_suffix_get_classes($extension_name, $expected) { $extension = $this->extension_manager->get_extension($extension_name); - $this->assertEquals($expected, self::$reflection_method_get_migration_file_list->invoke($extension)); + $migration_classes = self::$reflection_method_get_migration_file_list->invoke($extension); + sort($migration_classes); + $this->assertEquals($expected, $migration_classes); } } diff --git a/tests/extension/finder_test.php b/tests/extension/finder_test.php index 2116cc057b..463b69e9a9 100644 --- a/tests/extension/finder_test.php +++ b/tests/extension/finder_test.php @@ -244,7 +244,7 @@ class phpbb_extension_finder_test extends phpbb_test_case public function test_get_classes_create_cache() { $cache = new phpbb_mock_cache; - $finder = new \phpbb\finder(new \phpbb\filesystem(), dirname(__FILE__) . '/', $cache, 'php', '_custom_cache_name'); + $finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), dirname(__FILE__) . '/', $cache, 'php', '_custom_cache_name'); $finder->set_extensions(array_keys($this->extension_manager->all_enabled())); $files = $finder->suffix('_class.php')->get_files(); @@ -284,7 +284,7 @@ class phpbb_extension_finder_test extends phpbb_test_case ); $finder = new \phpbb\finder( - new \phpbb\filesystem(), + new \phpbb\filesystem\filesystem(), dirname(__FILE__) . '/', new phpbb_mock_cache(array( '_ext_finder' => array( diff --git a/tests/extension/includes/acp/info/acp_foobar.php b/tests/extension/includes/acp/info/acp_foobar.php index 870225ba4f..8ca1afa1c6 100644 --- a/tests/extension/includes/acp/info/acp_foobar.php +++ b/tests/extension/includes/acp/info/acp_foobar.php @@ -18,7 +18,6 @@ class acp_foobar_info return array( 'filename' => 'acp_foobar', 'title' => 'ACP Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'test' => array('title' => 'Test', 'auth' => '', 'cat' => array('ACP_GENERAL')), ), diff --git a/tests/extension/manager_test.php b/tests/extension/manager_test.php index 0eeb060936..a24b0cf178 100644 --- a/tests/extension/manager_test.php +++ b/tests/extension/manager_test.php @@ -150,11 +150,11 @@ class phpbb_extension_manager_test extends phpbb_database_test_case $config = new \phpbb\config\config(array('version' => PHPBB_VERSION)); $db = $this->new_dbal(); - $db_tools = new \phpbb\db\tools($db); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($db); $phpbb_root_path = __DIR__ . './../../phpBB/'; $php_ext = 'php'; $table_prefix = 'phpbb_'; - $user = new \phpbb\user('\phpbb\user'); $container = new phpbb_mock_container_builder(); @@ -176,8 +176,7 @@ class phpbb_extension_manager_test extends phpbb_database_test_case $container, $db, $config, - new \phpbb\filesystem(), - $user, + new \phpbb\filesystem\filesystem(), 'phpbb_ext', dirname(__FILE__) . '/', $php_ext, diff --git a/tests/extension/metadata_manager_test.php b/tests/extension/metadata_manager_test.php index 2a746d3792..53bd3d109b 100644 --- a/tests/extension/metadata_manager_test.php +++ b/tests/extension/metadata_manager_test.php @@ -41,25 +41,40 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case 'version' => '3.1.0', )); $this->db = $this->new_dbal(); - $this->db_tools = new \phpbb\db\tools($this->db); + $factory = new \phpbb\db\tools\factory(); + $this->db_tools = $factory->get($this->db); $this->phpbb_root_path = dirname(__FILE__) . '/'; $this->phpEx = 'php'; - $this->user = new \phpbb\user('\phpbb\datetime'); $this->table_prefix = 'phpbb_'; - $this->template = new \phpbb\template\twig\twig( - new \phpbb\path_helper( - new \phpbb\symfony_request( - new phpbb_mock_request() - ), - new \phpbb\filesystem(), - $this->getMock('\phpbb\request\request'), - $this->phpbb_root_path, - $this->phpEx + $container = new phpbb_mock_container_builder(); + $cache_path = $this->phpbb_root_path . 'cache/twig'; + $context = new \phpbb\template\context(); + $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), ''); + $filesystem = new \phpbb\filesystem\filesystem(); + $phpbb_path_helper = new \phpbb\path_helper( + new \phpbb\symfony_request( + new phpbb_mock_request() ), + $filesystem, + $this->getMock('\phpbb\request\request'), + $this->phpbb_root_path, + $this->phpEx + ); + $twig = new \phpbb\template\twig\environment( $this->config, - $this->user, - new \phpbb\template\context() + $filesystem, + $phpbb_path_helper, + $container, + $cache_path, + null, + $loader, + array( + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ) ); $container = new phpbb_mock_container_builder(); @@ -82,13 +97,22 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case $container, $this->db, $this->config, - new \phpbb\filesystem(), - $this->user, + new \phpbb\filesystem\filesystem(), 'phpbb_ext', $this->phpbb_root_path, $this->phpEx, $this->cache ); + + global $phpbb_root_path; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $this->phpEx); + $lang_loader->set_extension_manager($this->extension_manager); + $lang = new \phpbb\language\language($lang_loader); + $this->user = new \phpbb\user($lang, '\phpbb\datetime'); + + $this->template = new phpbb\template\twig\twig($phpbb_path_helper, $this->config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user))); + $container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig)); } // Should fail from missing composer.json @@ -104,7 +128,8 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case } catch (\phpbb\extension\exception $e) { - $this->assertEquals((string) $e, $this->user->lang('FILE_NOT_FOUND', $this->phpbb_root_path . $this->extension_manager->get_extension_path($ext_name) . 'composer.json')); + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); + $this->assertEquals($message, $this->user->lang('FILE_NOT_FOUND', $this->phpbb_root_path . $this->extension_manager->get_extension_path($ext_name) . 'composer.json')); } } @@ -121,7 +146,8 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case } catch (\phpbb\extension\exception $e) { - $this->fail($e); + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); + $this->fail($message); } $json = json_decode(file_get_contents($this->phpbb_root_path . 'ext/vendor2/foo/composer.json'), true); @@ -151,9 +177,10 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case $manager->validate($field_name); $this->fail('Exception not triggered'); } - catch(\phpbb\extension\exception $e) + catch (\phpbb\extension\exception $e) { - $this->assertEquals((string) $e, $this->user->lang('META_FIELD_NOT_SET', $field_name)); + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); + $this->assertEquals($message, $this->user->lang('META_FIELD_NOT_SET', $field_name)); } } @@ -167,7 +194,8 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case } catch (\phpbb\extension\exception $e) { - $this->assertEquals((string) $e, $this->user->lang('META_FIELD_NOT_SET', 'authors')); + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); + $this->assertEquals($message, $this->user->lang('META_FIELD_NOT_SET', 'authors')); } $manager->merge_metadata(array( @@ -183,7 +211,8 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case } catch (\phpbb\extension\exception $e) { - $this->assertEquals((string) $e, $this->user->lang('META_FIELD_NOT_SET', 'author name')); + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); + $this->assertEquals($message, $this->user->lang('META_FIELD_NOT_SET', 'author name')); } } @@ -214,9 +243,10 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case $manager->validate($field_name); $this->fail('Exception not triggered'); } - catch(\phpbb\extension\exception $e) + catch (\phpbb\extension\exception $e) { - $this->assertEquals((string) $e, $this->user->lang('META_FIELD_INVALID', $field_name)); + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); + $this->assertEquals($message, $this->user->lang('META_FIELD_INVALID', $field_name)); } } @@ -238,9 +268,9 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case { $this->assertEquals(true, $manager->validate('enable')); } - catch(\phpbb\extension\exception $e) + catch (\phpbb\extension\exception $e) { - $this->fail($e); + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); } } @@ -336,7 +366,6 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case $this->config, $this->extension_manager, $this->template, - $this->user, $this->phpbb_root_path ); } diff --git a/tests/extension/modules_test.php b/tests/extension/modules_test.php index 21f1c6aca5..88634bc6ba 100644 --- a/tests/extension/modules_test.php +++ b/tests/extension/modules_test.php @@ -22,6 +22,7 @@ class phpbb_extension_modules_test extends phpbb_test_case { protected $extension_manager; protected $finder; + protected $module_manager; public function setUp() { @@ -43,7 +44,14 @@ class phpbb_extension_modules_test extends phpbb_test_case )); $phpbb_extension_manager = $this->extension_manager; - $this->acp_modules = new acp_modules(); + $this->module_manager = new \phpbb\module\module_manager( + new \phpbb\cache\driver\dummy(), + $this->getMock('\phpbb\db\driver\driver_interface'), + $this->extension_manager, + MODULES_TABLE, + dirname(__FILE__) . '/', + 'php' + ); } public function test_get_module_infos() @@ -56,13 +64,11 @@ class phpbb_extension_modules_test extends phpbb_test_case $phpbb_root_path = dirname(__FILE__) . '/'; // Find acp module info files - $this->acp_modules->module_class = 'acp'; - $acp_modules = $this->acp_modules->get_module_infos(); + $acp_modules = $this->module_manager->get_module_infos('acp'); $this->assertEquals(array( 'vendor2\\foo\\acp\\a_module' => array( 'filename' => 'vendor2\\foo\\acp\\a_module', 'title' => 'Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => 'ext_vendor2/foo', 'cat' => array('ACP_MODS')), ), @@ -70,7 +76,6 @@ class phpbb_extension_modules_test extends phpbb_test_case 'acp_foobar' => array( 'filename' => 'acp_foobar', 'title' => 'ACP Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'test' => array('title' => 'Test', 'auth' => '', 'cat' => array('ACP_GENERAL')), ), @@ -78,13 +83,11 @@ class phpbb_extension_modules_test extends phpbb_test_case ), $acp_modules); // Find mcp module info files - $this->acp_modules->module_class = 'mcp'; - $acp_modules = $this->acp_modules->get_module_infos(); + $acp_modules = $this->module_manager->get_module_infos('mcp'); $this->assertEquals(array( 'vendor2\\foo\\mcp\\a_module' => array( 'filename' => 'vendor2\\foo\\mcp\\a_module', 'title' => 'Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('MCP_MAIN')), ), @@ -92,27 +95,11 @@ class phpbb_extension_modules_test extends phpbb_test_case ), $acp_modules); // Find a specific module info file (mcp_a_module) - $this->acp_modules->module_class = 'mcp'; - $acp_modules = $this->acp_modules->get_module_infos('mcp_a_module'); - $this->assertEquals(array( - 'vendor2\\foo\\mcp\\a_module' => array( - 'filename' => 'vendor2\\foo\\mcp\\a_module', - 'title' => 'Foobar', - 'version' => '3.1.0-dev', - 'modes' => array( - 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('MCP_MAIN')), - ), - ), - ), $acp_modules); - - // Find a specific module info file (mcp_a_module) with passing the module_class - $this->acp_modules->module_class = ''; - $acp_modules = $this->acp_modules->get_module_infos('mcp_a_module', 'mcp'); + $acp_modules = $this->module_manager->get_module_infos('mcp', 'mcp_a_module'); $this->assertEquals(array( 'vendor2\\foo\\mcp\\a_module' => array( 'filename' => 'vendor2\\foo\\mcp\\a_module', 'title' => 'Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('MCP_MAIN')), ), @@ -120,23 +107,19 @@ class phpbb_extension_modules_test extends phpbb_test_case ), $acp_modules); // The mcp module info file we're looking for shouldn't exist - $this->acp_modules->module_class = 'mcp'; - $acp_modules = $this->acp_modules->get_module_infos('mcp_a_fail'); + $acp_modules = $this->module_manager->get_module_infos('mcp', 'mcp_a_fail'); $this->assertEquals(array(), $acp_modules); // As there are no ucp modules we shouldn't find any - $this->acp_modules->module_class = 'ucp'; - $acp_modules = $this->acp_modules->get_module_infos(); + $acp_modules = $this->module_manager->get_module_infos('ucp'); $this->assertEquals(array(), $acp_modules); // Get module info of specified extension module - $this->acp_modules->module_class = 'acp'; - $acp_modules = $this->acp_modules->get_module_infos('foo_acp_a_module'); + $acp_modules = $this->module_manager->get_module_infos('acp', 'foo_acp_a_module'); $this->assertEquals(array( 'vendor2\\foo\\acp\\a_module' => array ( 'filename' => 'vendor2\\foo\\acp\\a_module', 'title' => 'Foobar', - 'version' => '3.1.0-dev', 'modes' => array ( 'config' => array ('title' => 'Config', 'auth' => 'ext_vendor2/foo', 'cat' => array ('ACP_MODS')), ), @@ -144,23 +127,20 @@ class phpbb_extension_modules_test extends phpbb_test_case ), $acp_modules); // No specific module and module class set to an incorrect name - $acp_modules = $this->acp_modules->get_module_infos('', 'wcp', true); + $acp_modules = $this->module_manager->get_module_infos('wcp', '', true); $this->assertEquals(array(), $acp_modules); // No specific module, no module_class set in the function parameter, and an incorrect module class - $this->acp_modules->module_class = 'wcp'; - $acp_modules = $this->acp_modules->get_module_infos(); + $acp_modules = $this->module_manager->get_module_infos('wcp'); $this->assertEquals(array(), $acp_modules); // No specific module, module class set to false (will default to the above acp) // Setting $use_all_available will cause get_module_infos() to also load not enabled extensions (vendor2/bar) - $this->acp_modules->module_class = 'acp'; - $acp_modules = $this->acp_modules->get_module_infos('', false, true); + $acp_modules = $this->module_manager->get_module_infos('acp', '', true); $this->assertEquals(array( 'vendor2\\foo\\acp\\a_module' => array( 'filename' => 'vendor2\\foo\\acp\\a_module', 'title' => 'Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => 'ext_vendor2/foo', 'cat' => array('ACP_MODS')), ), @@ -168,7 +148,6 @@ class phpbb_extension_modules_test extends phpbb_test_case 'acp_foobar' => array( 'filename' => 'acp_foobar', 'title' => 'ACP Foobar', - 'version' => '3.1.0-dev', 'modes' => array( 'test' => array('title' => 'Test', 'auth' => '', 'cat' => array('ACP_GENERAL')), ), @@ -176,7 +155,6 @@ class phpbb_extension_modules_test extends phpbb_test_case 'vendor2\\bar\\acp\\a_module' => array( 'filename' => 'vendor2\\bar\\acp\\a_module', 'title' => 'Bar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('ACP_MODS')), ), @@ -184,12 +162,11 @@ class phpbb_extension_modules_test extends phpbb_test_case ), $acp_modules); // Specific module set to disabled extension - $acp_modules = $this->acp_modules->get_module_infos('vendor2_bar_acp_a_module', 'acp', true); + $acp_modules = $this->module_manager->get_module_infos('acp', 'vendor2_bar_acp_a_module', true); $this->assertEquals(array( 'vendor2\\bar\\acp\\a_module' => array( 'filename' => 'vendor2\\bar\\acp\\a_module', 'title' => 'Bar', - 'version' => '3.1.0-dev', 'modes' => array( 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('ACP_MODS')), ), diff --git a/tests/files/type_foo.php b/tests/files/type_foo.php new file mode 100644 index 0000000000..95940b9d2f --- /dev/null +++ b/tests/files/type_foo.php @@ -0,0 +1,31 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\files\types; + +class foo extends \phpbb\files\types\remote +{ + static public $tempnam_path; +} + +function tempnam($one, $two) +{ + if (empty(foo::$tempnam_path)) + { + return \tempnam($one, $two); + } + else + { + return foo::$tempnam_path; + } +} diff --git a/tests/files/types_base_test.php b/tests/files/types_base_test.php new file mode 100644 index 0000000000..e630bf8c48 --- /dev/null +++ b/tests/files/types_base_test.php @@ -0,0 +1,93 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_files_types_base_test extends phpbb_test_case +{ + private $path; + + private $filesystem; + + /** @var \Symfony\Component\DependencyInjection\ContainerInterface */ + protected $container; + + /** @var \phpbb\files\factory */ + protected $factory; + + /** @var \bantu\IniGetWrapper\IniGetWrapper */ + protected $php_ini; + + /** @var \phpbb\language\language */ + protected $language; + + /** @var \phpbb\request\request_interface */ + protected $request; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + + protected function setUp() + { + global $phpbb_root_path, $phpEx; + + $this->request = $this->getMock('\phpbb\request\request'); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper; + + $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx); + $this->container->set('files.filespec', new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + )))); + $this->factory = new \phpbb\files\factory($this->container); + + $this->path = __DIR__ . '/fixture/'; + $this->phpbb_root_path = $phpbb_root_path; + } + + public function data_check_upload_size() + { + return array( + array('foo', '500KB', array()), + array('none', '500KB', array('PHP_SIZE_OVERRUN')), + array('none', '', array('PHP_SIZE_NA')), + ); + } + + /** + * @dataProvider data_check_upload_size + */ + public function test_check_upload_size($filename, $max_filesize, $expected) + { + $php_ini = $this->getMock('\bantu\IniGetWrapper\IniGetWrapper'); + $php_ini->expects($this->any()) + ->method('getString') + ->willReturn($max_filesize); + $type_form = new \phpbb\files\types\local($this->factory, $this->language, $php_ini, $this->request); + $file = $this->getMockBuilder('\phpbb\files\filespec') + ->disableOriginalConstructor() + ->getMock(); + $file->expects($this->any()) + ->method('get') + ->willReturn($filename); + $type_form->check_upload_size($file); + + $this->assertSame($expected, $file->error); + } +} diff --git a/tests/files/types_form_test.php b/tests/files/types_form_test.php new file mode 100644 index 0000000000..efcece49d1 --- /dev/null +++ b/tests/files/types_form_test.php @@ -0,0 +1,174 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + +class phpbb_files_types_form_test extends phpbb_test_case +{ + private $path; + + private $filesystem; + + /** @var \Symfony\Component\DependencyInjection\ContainerInterface */ + protected $container; + + /** @var \phpbb\files\factory */ + protected $factory; + + /** @var \bantu\IniGetWrapper\IniGetWrapper */ + protected $php_ini; + + /** @var \phpbb\language\language */ + protected $language; + + /** @var \phpbb\request\request_interface */ + protected $request; + + /** @var \phpbb\plupload\plupload */ + protected $plupload; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + + protected function setUp() + { + global $phpbb_root_path, $phpEx; + + $this->request = $this->getMock('\phpbb\request\request'); + $this->request->expects($this->any()) + ->method('file') + ->willReturn(array()); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper; + + $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx); + $this->container->set('files.filespec', new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + )))); + $this->factory = new \phpbb\files\factory($this->container); + $this->plupload = $this->getMockBuilder('\phpbb\plupload\plupload') + ->disableOriginalConstructor() + ->getMock(); + $this->plupload->expects($this->any()) + ->method('handle_upload') + ->willReturn(array()); + + $this->path = __DIR__ . '/fixture/'; + $this->phpbb_root_path = $phpbb_root_path; + } + + public function data_upload_form() + { + return array( + array( + array(), + array(''), + ), + array( + array( + 'tmp_name' => 'foo', + 'name' => 'foo', + 'size' => 500, + 'type' => 'image/png', + 'error' => UPLOAD_ERR_PARTIAL, + ), + array('PARTIAL_UPLOAD'), + ), + array( + array( + 'tmp_name' => 'foo', + 'name' => 'foo', + 'size' => 500, + 'type' => 'image/png', + 'error' => -9, + ), + array('NOT_UPLOADED'), + ), + array( + array( + 'tmp_name' => 'foo', + 'name' => 'foo', + 'size' => 0, + 'type' => 'image/png', + ), + array('EMPTY_FILEUPLOAD'), + ), + array( + array( + 'tmp_name' => 'none', + 'name' => 'none', + 'size' => 50, + 'type' => 'image/png', + ), + array('PHP_SIZE_OVERRUN'), + ), + array( + array( + 'tmp_name' => 'tests/upload/fixture/png', + 'name' => 'foo.png', + 'size' => 500, + 'type' => 'image/png', + 'local_mode' => true, + ), + array(), + array('local_mode' => true), + ), + ); + } + + /** + * @dataProvider data_upload_form + */ + public function test_upload_form($upload, $expected, $plupload = array()) + { + $this->request = $this->getMock('\phpbb\request\request'); + $this->request->expects($this->any()) + ->method('file') + ->willReturn($upload); + $filespec = new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $this->phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + ))); + $this->container->set('files.filespec', $filespec); + $this->factory = new \phpbb\files\factory($this->container); + $this->plupload = $this->getMockBuilder('\phpbb\plupload\plupload') + ->disableOriginalConstructor() + ->getMock(); + $this->plupload->expects($this->any()) + ->method('handle_upload') + ->willReturn($plupload); + + $type_form = new \phpbb\files\types\form($this->factory, $this->language, $this->php_ini, $this->plupload, $this->request); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('png')); + $type_form->set_upload($upload); + + + $file = $type_form->upload('foobar'); + $this->assertSame($expected, $file->error); + $this->assertInstanceOf('\phpbb\files\filespec', $file); + } +} diff --git a/tests/files/types_local_test.php b/tests/files/types_local_test.php new file mode 100644 index 0000000000..f4fa7fad3f --- /dev/null +++ b/tests/files/types_local_test.php @@ -0,0 +1,163 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + +class phpbb_files_types_local_test extends phpbb_test_case +{ + private $path; + + private $filesystem; + + /** @var \Symfony\Component\DependencyInjection\ContainerInterface */ + protected $container; + + /** @var \phpbb\files\factory */ + protected $factory; + + /** @var \bantu\IniGetWrapper\IniGetWrapper */ + protected $php_ini; + + /** @var \phpbb\language\language */ + protected $language; + + /** @var \phpbb\request\request_interface */ + protected $request; + + /** @var \phpbb\plupload\plupload */ + protected $plupload; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + + protected function setUp() + { + global $phpbb_root_path, $phpEx; + + $this->request = $this->getMock('\phpbb\request\request'); + $this->request->expects($this->any()) + ->method('file') + ->willReturn(array()); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper; + + $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx); + $this->container->set('files.filespec', new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + )))); + $this->factory = new \phpbb\files\factory($this->container); + $this->plupload = $this->getMockBuilder('\phpbb\plupload\plupload') + ->disableOriginalConstructor() + ->getMock(); + $this->plupload->expects($this->any()) + ->method('handle_upload') + ->willReturn(array()); + + $this->path = __DIR__ . '/fixture/'; + $this->phpbb_root_path = $phpbb_root_path; + } + + public function test_upload_init_error() + { + $filespec = $this->getMockBuilder('\phpbb\files\filespec') + ->disableOriginalConstructor() + ->getMock(); + $filespec->expects($this->any()) + ->method('init_error') + ->willReturn(true); + $filespec->expects($this->any()) + ->method('set_upload_ary') + ->willReturnSelf(); + $filespec->expects($this->any()) + ->method('set_upload_namespace') + ->willReturnSelf(); + $this->container->set('files.filespec', $filespec); + $this->factory = new \phpbb\files\factory($this->container); + + $type_local = new \phpbb\files\types\local($this->factory, $this->language, $this->php_ini, $this->request); + + + $file = $type_local->upload('foo', false); + $this->assertSame(array(''), $file->error); + $this->assertInstanceOf('\phpbb\files\filespec', $file); + } + + public function data_upload_form() + { + return array( + array( + 'foo', + array( + 'tmp_name' => 'foo', + 'size' => 500, + 'type' => 'image/png', + ), + array('NOT_UPLOADED'), + ), + array( + 'none', + false, + array('PHP_SIZE_OVERRUN'), + ), + array( + 'tests/upload/fixture/png', + array( + 'realname' => 'foo.png', + 'size' => 500, + 'type' => 'image/png', + 'local_mode' => true, + ), + array(), + ), + ); + } + + /** + * @dataProvider data_upload_form + */ + public function test_upload_form($filename, $upload_ary, $expected) + { + $filespec = new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $this->phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + ))); + $filespec_local = new ReflectionProperty($filespec, 'local'); + $filespec_local->setAccessible(true); + $filespec_local->setValue($filespec, true); + $this->container->set('files.filespec', $filespec); + $this->factory = new \phpbb\files\factory($this->container); + + $type_local = new \phpbb\files\types\local($this->factory, $this->language, $this->php_ini, $this->request); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('png')); + $type_local->set_upload($upload); + + + $file = $type_local->upload($filename, $upload_ary); + $this->assertSame($expected, $file->error); + $this->assertInstanceOf('\phpbb\files\filespec', $file); + } +} diff --git a/tests/files/types_remote_test.php b/tests/files/types_remote_test.php new file mode 100644 index 0000000000..476d8ed3ba --- /dev/null +++ b/tests/files/types_remote_test.php @@ -0,0 +1,133 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/type_foo.php'; + +class phpbb_files_types_remote_test extends phpbb_test_case +{ + private $path; + + private $filesystem; + + /** @var \phpbb\config\config */ + protected $config; + + /** @var \Symfony\Component\DependencyInjection\ContainerInterface */ + protected $container; + + /** @var \phpbb\files\factory */ + protected $factory; + + /** @var \bantu\IniGetWrapper\IniGetWrapper */ + protected $php_ini; + + /** @var \phpbb\language\language */ + protected $language; + + /** @var \phpbb\request\request_interface */ + protected $request; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + + protected function setUp() + { + global $config, $phpbb_root_path, $phpEx; + + $config = new \phpbb\config\config(array()); + $this->config = $config; + $this->config->set('remote_upload_verify', 0); + $this->request = $this->getMock('\phpbb\request\request'); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper; + + $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx); + $this->container->set('files.filespec', new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + )))); + $this->factory = new \phpbb\files\factory($this->container); + + $this->path = __DIR__ . '/fixture/'; + $this->phpbb_root_path = $phpbb_root_path; + } + + public function test_upload_fsock_fail() + { + $type_remote = new \phpbb\files\types\remote($this->config, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('png')); + $type_remote->set_upload($upload); + + $file = $type_remote->upload('https://bärföö.com/foo.png'); + + $this->assertSame(array('NOT_UPLOADED'), $file->error); + } + + public function data_get_max_file_size() + { + return array( + array('', 'http://example.com/foo/bar.png'), + array('2k', 'http://example.com/foo/bar.png'), + array('500k', 'http://example.com/foo/bar.png'), + array('500M', 'http://example.com/foo/bar.png'), + array('500m', 'http://example.com/foo/bar.png'), + array('500k', 'http://google.com/?.png', array('DISALLOWED_EXTENSION', 'DISALLOWED_CONTENT')), + array('1', 'http://google.com/?.png', array('WRONG_FILESIZE')), + array('500g', 'http://example.com/foo/bar.png'), + array('foobar', 'http://example.com/foo/bar.png'), + array('-5k', 'http://example.com/foo/bar.png'), + ); + } + + /** + * @dataProvider data_get_max_file_size + */ + public function test_get_max_file_size($max_file_size, $link, $expected = array('URL_NOT_FOUND')) + { + $php_ini = $this->getMock('\bantu\IniGetWrapper\IniGetWrapper', array('getString')); + $php_ini->expects($this->any()) + ->method('getString') + ->willReturn($max_file_size); + $type_remote = new \phpbb\files\types\remote($this->config, $this->factory, $this->language, $php_ini, $this->request, $this->phpbb_root_path); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('png')); + $type_remote->set_upload($upload); + + $file = $type_remote->upload($link); + + $this->assertSame($expected, $file->error); + } + + public function test_upload_wrong_path() + { + $type_remote = new \phpbb\files\types\foo($this->config, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('png')); + $type_remote->set_upload($upload); + $type_remote::$tempnam_path = $this->phpbb_root_path . 'cache/wrong/path'; + + $file = $type_remote->upload('http://google.com/?.png'); + + $this->assertSame(array('NOT_UPLOADED'), $file->error); + $type_remote::$tempnam_path = ''; + } +} diff --git a/tests/files/upload_test.php b/tests/files/upload_test.php new file mode 100644 index 0000000000..c41204a0d5 --- /dev/null +++ b/tests/files/upload_test.php @@ -0,0 +1,128 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_files_upload_test extends phpbb_test_case +{ + private $path; + + private $filesystem; + + /** @var \Symfony\Component\DependencyInjection\ContainerInterface */ + protected $container; + + /** @var \phpbb\files\factory */ + protected $factory; + + /** @var \bantu\IniGetWrapper\IniGetWrapper */ + protected $php_ini; + + /** @var \phpbb\language\language */ + protected $language; + + /** @var \phpbb\request\request_interface */ + protected $request; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + + protected function setUp() + { + // Global $config required by unique_id + global $config, $phpbb_root_path, $phpEx; + + if (!is_array($config)) + { + $config = array(); + } + + $config['rand_seed'] = ''; + $config['rand_seed_last_update'] = time() + 600; + + $this->request = $this->getMock('\phpbb\request\request'); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper; + + $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx); + $this->container->set('files.filespec', new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + )))); + $this->factory = new \phpbb\files\factory($this->container); + + $this->path = __DIR__ . '/fixture/'; + $this->phpbb_root_path = $phpbb_root_path; + } + + public function test_reset_vars() + { + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_max_filesize(500); + $this->assertEquals(500, $upload->max_filesize); + $upload->reset_vars(); + $this->assertEquals(0, $upload->max_filesize); + } + + public function test_set_disallowed_content() + { + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $disallowed_content = new ReflectionProperty($upload, 'disallowed_content'); + $disallowed_content->setAccessible(true); + + $upload->set_disallowed_content(array('foo')); + $this->assertEquals(array('foo'), $disallowed_content->getValue($upload)); + $upload->set_disallowed_content(array('foo', 'bar', 'meh')); + $this->assertEquals(array('foo', 'bar', 'meh'), $disallowed_content->getValue($upload)); + $upload->set_disallowed_content(''); + $this->assertEquals(array('foo', 'bar', 'meh'), $disallowed_content->getValue($upload)); + $this->assertINstanceOf('\phpbb\files\upload', $upload->set_disallowed_content(array())); + $this->assertEquals(array(), $disallowed_content->getValue($upload)); + $upload->reset_vars(); + $this->assertEquals(array(), $disallowed_content->getValue($upload)); + } + + public function test_is_valid() + { + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $this->assertFalse($upload->is_valid('foobar')); + } + + public function data_internal_error() + { + return array( + array(UPLOAD_ERR_INI_SIZE, 'PHP_SIZE_OVERRUN'), + array(UPLOAD_ERR_FORM_SIZE, 'WRONG_FILESIZE'), + array(UPLOAD_ERR_PARTIAL, 'PARTIAL_UPLOAD'), + array(UPLOAD_ERR_NO_FILE, 'NOT_UPLOADED'), + array(UPLOAD_ERR_NO_TMP_DIR, 'NO_TEMP_DIR'), + array(UPLOAD_ERR_CANT_WRITE, 'NO_TEMP_DIR'), + array(UPLOAD_ERR_EXTENSION, 'PHP_UPLOAD_STOPPED'), + array(9, false), + ); + } + + /** + * @dataProvider data_internal_error + */ + public function test_assign_internal_error($error_code, $expected) + { + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $this->assertSame($expected, $upload->assign_internal_error($error_code)); + } +} diff --git a/tests/filesystem/clean_path_test.php b/tests/filesystem/clean_path_test.php index c585b17155..d2dec424b4 100644 --- a/tests/filesystem/clean_path_test.php +++ b/tests/filesystem/clean_path_test.php @@ -18,7 +18,7 @@ class phpbb_filesystem_clean_path_test extends phpbb_test_case public function setUp() { parent::setUp(); - $this->filesystem = new \phpbb\filesystem(); + $this->filesystem = new \phpbb\filesystem\filesystem(); } public function clean_path_data() diff --git a/tests/functions/is_absolute_test.php b/tests/filesystem/is_absolute_test.php index afa4b9b59f..7a50989b74 100644 --- a/tests/functions/is_absolute_test.php +++ b/tests/filesystem/is_absolute_test.php @@ -1,20 +1,28 @@ <?php /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; - -class phpbb_functions_is_absolute_test extends phpbb_test_case + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_filesystem_is_absolute_test extends phpbb_test_case { + /** @var \phpbb\filesystem\filesystem_interface */ + protected $filesystem; + + public function setUp() + { + parent::setUp(); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + } + static public function is_absolute_data() { return array( @@ -51,10 +59,10 @@ class phpbb_functions_is_absolute_test extends phpbb_test_case } /** - * @dataProvider is_absolute_data - */ + * @dataProvider is_absolute_data + */ public function test_is_absolute($path, $expected) { - $this->assertEquals($expected, phpbb_is_absolute($path)); + $this->assertEquals($expected, $this->filesystem->is_absolute_path($path)); } } diff --git a/tests/filesystem/realpath_test.php b/tests/filesystem/realpath_test.php new file mode 100644 index 0000000000..d994935f94 --- /dev/null +++ b/tests/filesystem/realpath_test.php @@ -0,0 +1,90 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_filesystem_realpath_test extends phpbb_test_case +{ + static protected $filesystem_own_realpath; + + /** @var \phpbb\filesystem\filesystem_interface */ + protected $filesystem; + + static public function setUpBeforeClass() + { + parent::setUpBeforeClass(); + + $reflection_class = new ReflectionClass('\phpbb\filesystem\filesystem'); + self::$filesystem_own_realpath = $reflection_class->getMethod('phpbb_own_realpath'); + self::$filesystem_own_realpath->setAccessible(true); + } + + public function setUp() + { + parent::setUp(); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + } + + public function realpath_resolve_absolute_without_symlinks_data() + { + return array( + // Constant data + array(__DIR__, __DIR__), + array(__DIR__ . '/../filesystem/../filesystem', __DIR__), + array(__DIR__ . '/././', __DIR__), + array(__DIR__ . '/non_existent', false), + + array(__FILE__, __FILE__), + array(__FILE__ . '../', false), + ); + } + + public function realpath_resolve_relative_without_symlinks_data() + { + if (!function_exists('getcwd')) + { + return array(); + } + + $filesystem = new \phpbb\filesystem\filesystem(); + $relative_path = $filesystem->make_path_relative(__DIR__, getcwd()); + + return array( + array($relative_path, __DIR__), + array($relative_path . '../filesystem/../filesystem', __DIR__), + array($relative_path . '././', __DIR__), + + array($relative_path . 'realpath_test.php', __FILE__), + ); + } + + /** + * @dataProvider realpath_resolve_absolute_without_symlinks_data + */ + public function test_realpath_absolute_without_links($path, $expected) + { + $this->assertEquals($expected, self::$filesystem_own_realpath->invoke($this->filesystem, $path)); + } + + /** + * @dataProvider realpath_resolve_relative_without_symlinks_data + */ + public function test_realpath_relative_without_links($path, $expected) + { + if (!function_exists('getcwd')) + { + $this->markTestSkipped('phpbb_own_realpath() cannot be tested with relative paths: getcwd is not available.'); + } + + $this->assertEquals($expected, self::$filesystem_own_realpath->invoke($this->filesystem, $path)); + } +} diff --git a/tests/functional/browse_test.php b/tests/functional/browse_test.php index b9e74a280f..280e814c06 100644 --- a/tests/functional/browse_test.php +++ b/tests/functional/browse_test.php @@ -34,9 +34,21 @@ class phpbb_functional_browse_test extends phpbb_functional_test_case $this->assertGreaterThan(0, $crawler->filter('.postbody')->count()); } + public function test_help_faq() + { + $crawler = self::request('GET', 'app.php/help/faq'); + $this->assertGreaterThan(0, $crawler->filter('h2.faq-title')->count()); + } + + public function test_help_bbcode() + { + $crawler = self::request('GET', 'app.php/help/bbcode'); + $this->assertGreaterThan(0, $crawler->filter('h2.faq-title')->count()); + } + public function test_feed() { - $crawler = self::request('GET', 'feed.php', array(), false); + $crawler = self::request('GET', 'app.php/feed', array(), false); self::assert_response_xml(); $this->assertGreaterThan(0, $crawler->filter('entry')->count()); } diff --git a/tests/functional/controllers_compatibility_test.php b/tests/functional/controllers_compatibility_test.php new file mode 100644 index 0000000000..9499888a1a --- /dev/null +++ b/tests/functional/controllers_compatibility_test.php @@ -0,0 +1,56 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +/** +* @group functional +*/ + +class phpbb_functional_controllers_compatibility_test extends phpbb_functional_test_case +{ + public function test_report_compatibility() + { + $this->assert301('report.php?f=1&p=1', 'app.php/post/1/report'); + $this->assert301('report.php?p=1', 'app.php/post/1/report'); + $this->assert301('report.php?pm=1', 'app.php/pm/1/report'); + } + + public function test_feed_compatibility() + { + $this->assert301('feed.php', 'app.php/feed'); + $this->assert301('feed.php?mode=foobar', 'app.php/feed/foobar'); + $this->assert301('feed.php?mode=news', 'app.php/feed/news'); + $this->assert301('feed.php?mode=topics', 'app.php/feed/topics'); + $this->assert301('feed.php?mode=topics_news', 'app.php/feed/topics_news'); + $this->assert301('feed.php?mode=topics_active', 'app.php/feed/topics_active'); + $this->assert301('feed.php?mode=forums', 'app.php/feed/forums'); + $this->assert301('feed.php?f=1', 'app.php/feed/forum/1'); + $this->assert301('feed.php?t=1', 'app.php/feed/topic/1'); + } + + protected function assert301($from, $to) + { + self::$client->followRedirects(false); + self::request('GET', $from, array(), false); + + // Fix sid issues + $location = self::$client->getResponse()->getHeader('Location'); + $location = preg_replace('#sid=[^&]+(&(amp;)?)?#', '', $location); + if (substr($location, -1) === '?') + { + $location = substr($location, 0, -1); + } + + $this->assertEquals(301, self::$client->getResponse()->getStatus()); + $this->assertStringEndsWith($to, $location); + } +} diff --git a/tests/functional/extension_module_test.php b/tests/functional/extension_module_test.php index ee084720e4..95107665cd 100644 --- a/tests/functional/extension_module_test.php +++ b/tests/functional/extension_module_test.php @@ -49,8 +49,9 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case $this->phpbb_extension_manager = $this->get_extension_manager(); $this->phpbb_extension_manager->enable('foo/bar'); - $modules = new acp_modules(); $db = $this->get_db(); + $cache = $this->get_cache_driver(); + $modules = new \phpbb\module\module_manager($cache, $db, $this->phpbb_extension_manager, MODULES_TABLE, dirname(__FILE__) . '/../../phpBB/', 'php'); $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " @@ -70,7 +71,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case 'module_mode' => '', 'module_auth' => '', ); - $modules->update_module_data($parent_data, true); + $modules->update_module_data($parent_data); $module_data = array( 'module_basename' => 'foo\\bar\\acp\\main_module', @@ -82,7 +83,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case 'module_mode' => 'mode', 'module_auth' => '', ); - $modules->update_module_data($module_data, true); + $modules->update_module_data($module_data); $parent_data = array( 'module_basename' => '', @@ -94,7 +95,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case 'module_mode' => '', 'module_auth' => '', ); - $modules->update_module_data($parent_data, true); + $modules->update_module_data($parent_data); $module_data = array( 'module_basename' => 'foo\\bar\\ucp\\main_module', @@ -106,7 +107,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case 'module_mode' => 'mode', 'module_auth' => '', ); - $modules->update_module_data($module_data, true); + $modules->update_module_data($module_data); $this->purge_cache(); } diff --git a/tests/functional/feed_test.php b/tests/functional/feed_test.php index e48dfc043a..dad5ca7e1a 100644 --- a/tests/functional/feed_test.php +++ b/tests/functional/feed_test.php @@ -11,6 +11,8 @@ * */ +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + /** * @group functional */ @@ -30,9 +32,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case { parent::__construct($name, $data, $dataName); - $this->backupStaticAttributesBlacklist += array( - 'phpbb_functional_feed_test' => array('init_values'), - ); + $this->backupStaticAttributesBlacklist['phpbb_functional_feed_test'] = array('init_values'); + + $this->purge_cache(); } public function test_setup_config_before_state() @@ -61,66 +63,64 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $form->setValues($values); $crawler = self::submit($form); - $this->assertContainsLang('CONFIG_UPDATED', $crawler->filter('.successbox')->text()); + self::assertContainsLang('CONFIG_UPDATED', $crawler->filter('.successbox')->text()); // Special config (Guest can't see attachments) $this->add_lang('acp/permissions'); $crawler = self::request('GET', "adm/index.php?i=acp_permissions&sid={$this->sid}&icat=16&mode=setting_group_global&group_id[0]=1"); - $this->assertContains($this->lang('ACL_SET'), $crawler->filter('h1')->eq(1)->text()); + self::assertContains($this->lang('ACL_SET'), $crawler->filter('h1')->eq(1)->text()); $form = $crawler->selectButton($this->lang('APPLY_PERMISSIONS'))->form(); $form['setting[1][0][u_download]']->select(-1); $crawler = self::submit($form); - $this->assertContainsLang('AUTH_UPDATED', $crawler->filter('.successbox')->text()); + self::assertContainsLang('AUTH_UPDATED', $crawler->filter('.successbox')->text()); } public function test_dump_board_state() { - $crawler = self::request('GET', 'feed.php?mode=forums', array(), false); + $crawler = self::request('GET', 'app.php/feed/forums', array(), false); self::assert_response_xml(); self::$init_values['disapprove_user']['forums_value'] = $crawler->filterXPath('//entry')->count(); - $crawler = self::request('GET', 'feed.php?mode=overall', array(), false); + $crawler = self::request('GET', 'app.php/feed/overall', array(), false); self::assert_response_xml(); self::$init_values['disapprove_user']['overall_value'] = $crawler->filterXPath('//entry')->count(); - $crawler = self::request('GET', 'feed.php?mode=topics', array(), false); + $crawler = self::request('GET', 'app.php/feed/topics', array(), false); self::assert_response_xml(); self::$init_values['disapprove_user']['topics_value'] = $crawler->filterXPath('//entry')->count(); - $crawler = self::request('GET', 'feed.php?mode=topics_new', array(), false); + $crawler = self::request('GET', 'app.php/feed/topics_new', array(), false); self::assert_response_xml(); self::$init_values['disapprove_user']['topics_new_value'] = $crawler->filterXPath('//entry')->count(); - $crawler = self::request('GET', 'feed.php?mode=topics_active', array(), false); + $crawler = self::request('GET', 'app.php/feed/topics_active', array(), false); self::assert_response_xml(); self::$init_values['disapprove_user']['topics_active_value'] = $crawler->filterXPath('//entry')->count(); $this->login(); - $crawler = self::request('GET', 'feed.php?mode=forums', array(), false); + $crawler = self::request('GET', 'app.php/feed/forums', array(), false); self::assert_response_xml(); self::$init_values['admin']['forums_value'] = $crawler->filterXPath('//entry')->count(); - $crawler = self::request('GET', 'feed.php?mode=overall', array(), false); + $crawler = self::request('GET', 'app.php/feed/overall', array(), false); self::assert_response_xml(); self::$init_values['admin']['overall_value'] = $crawler->filterXPath('//entry')->count(); - $crawler = self::request('GET', 'feed.php?mode=topics', array(), false); + $crawler = self::request('GET', 'app.php/feed/topics', array(), false); self::assert_response_xml(); self::$init_values['admin']['topics_value'] = $crawler->filterXPath('//entry')->count(); - $crawler = self::request('GET', 'feed.php?mode=topics_new', array(), false); + $crawler = self::request('GET', 'app.php/feed/topics_new', array(), false); self::assert_response_xml(); self::$init_values['admin']['topics_new_value'] = $crawler->filterXPath('//entry')->count(); - $crawler = self::request('GET', 'feed.php?mode=topics_active', array(), false); + $crawler = self::request('GET', 'app.php/feed/topics_active', array(), false); self::assert_response_xml(); self::$init_values['admin']['topics_active_value'] = $crawler->filterXPath('//entry')->count(); - - } public function test_setup_forums() @@ -138,7 +138,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $form = $crawler->selectButton('update')->form(array( 'forum_perm_from' => 2, )); - $crawler = self::submit($form); + self::submit($form); $this->load_ids(array( 'forums' => array( @@ -155,7 +155,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $form = $crawler->selectButton('update')->form(array( 'forum_perm_from' => 2, )); - $crawler = self::submit($form); + self::submit($form); // 'Feeds #news' will be used for feed.php?mode=news $crawler = self::request('GET', "adm/index.php?i=acp_forums&mode=manage&sid={$this->sid}"); @@ -166,9 +166,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $form = $crawler->selectButton('update')->form(array( 'forum_perm_from' => 2, )); - $crawler = self::submit($form); + self::submit($form); - // 'Feeds #exclude' will not be displayed on feed.php?mode=forums + // 'Feeds #exclude' will not be displayed on app.php/feed/forums $crawler = self::request('GET', "adm/index.php?i=acp_forums&mode=manage&sid={$this->sid}"); $form = $crawler->selectButton('addforum')->form(array( 'forum_name' => 'Feeds #exclude', @@ -177,7 +177,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $form = $crawler->selectButton('update')->form(array( 'forum_perm_from' => 2, )); - $crawler = self::submit($form); + self::submit($form); } public function test_setup_config_after_forums() @@ -201,7 +201,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $form['feed_exclude_id']->select(array($this->data['forums']['Feeds #exclude'])); $crawler = self::submit($form); - $this->assertContainsLang('CONFIG_UPDATED', $crawler->filter('.successbox')->text()); + self::assertContainsLang('CONFIG_UPDATED', $crawler->filter('.successbox')->text()); } public function test_feeds_empty() @@ -272,6 +272,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case 'id' => $this->data['forums']['Feeds #exclude'], 'contents_lang' => array('NO_FEED'), 'invalid' => true, + 'response_code' => 404, ), ), 't' => array( @@ -279,6 +280,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case 'id' => $this->data['topics']['Feeds #exclude - Topic #1'], 'contents_lang' => array('NO_FEED'), 'invalid' => true, + 'response_code' => 404, ), ), 'overall' => array( @@ -331,7 +333,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $post = $this->create_topic($this->data['forums']['Feeds #news'], 'Feeds #news - Topic #2', 'This is a test topic posted by the testing framework.'); $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}"); - $this->assertContains('Feeds #news - Topic #2', $crawler->filter('html')->text()); + self::assertContains('Feeds #news - Topic #2', $crawler->filter('html')->text()); $this->data['topics']['Feeds #news - Topic #2'] = (int) $post['topic_id']; $this->data['posts']['Feeds #news - Topic #2'] = (int) $this->get_parameter_from_link($crawler->filter('.post')->selectLink($this->lang('POST', '', ''))->link()->getUri(), 'p'); @@ -339,7 +341,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $post2 = $this->create_post($this->data['forums']['Feeds #news'], $post['topic_id'], 'Re: Feeds #news - Topic #2', 'This is a test post posted by the testing framework.'); $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}"); - $this->assertContains('Re: Feeds #news - Topic #2', $crawler->filter('html')->text()); + self::assertContains('Re: Feeds #news - Topic #2', $crawler->filter('html')->text()); $this->data['posts']['Re: Feeds #news - Topic #2'] = (int) $post2['post_id']; } @@ -495,7 +497,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $post2 = $this->create_post($this->data['forums']['Feeds #1'], $post['topic_id'], 'Re: Feeds #1 - Topic #2', 'This is a test post posted by the testing framework.'); $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}"); - $this->assertContains('Re: Feeds #1 - Topic #2', $crawler->filter('html')->text()); + self::assertContains('Re: Feeds #1 - Topic #2', $crawler->filter('html')->text()); $this->data['posts']['Re: Feeds #1 - Topic #2'] = (int) $post2['post_id']; } @@ -516,14 +518,14 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $this->add_lang('posting'); $crawler = self::request('GET', "posting.php?mode=delete&f={$this->data['forums']['Feeds #1']}&p={$this->data['posts']['Re: Feeds #1 - Topic #2']}&sid={$this->sid}"); - $this->assertContainsLang('DELETE_PERMANENTLY', $crawler->text()); + self::assertContainsLang('DELETE_PERMANENTLY', $crawler->text()); $form = $crawler->selectButton('Yes')->form(); $crawler = self::submit($form); - $this->assertContainsLang('POST_DELETED', $crawler->text()); + self::assertContainsLang('POST_DELETED', $crawler->text()); $crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Feeds #1 - Topic #2']}&sid={$this->sid}"); - $this->assertContains($this->lang('POST_DISPLAY', '', ''), $crawler->text()); + self::assertContains($this->lang('POST_DISPLAY', '', ''), $crawler->text()); } public function test_feeds_softdeleted_post_admin() @@ -615,15 +617,15 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $this->add_lang('posting'); $crawler = $this->get_quickmod_page($this->data['topics']['Feeds #1 - Topic #2'], 'DELETE_TOPIC'); - $this->assertContainsLang('DELETE_PERMANENTLY', $crawler->text()); + self::assertContainsLang('DELETE_PERMANENTLY', $crawler->text()); $this->add_lang('mcp'); $form = $crawler->selectButton('Yes')->form(); $crawler = self::submit($form); - $this->assertContainsLang('TOPIC_DELETED_SUCCESS', $crawler->text()); + self::assertContainsLang('TOPIC_DELETED_SUCCESS', $crawler->text()); $crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Feeds #1 - Topic #2']}&sid={$this->sid}"); - $this->assertContains('Feeds #1 - Topic #2', $crawler->filter('h2')->text()); + self::assertContains('Feeds #1 - Topic #2', $crawler->filter('h2')->text()); } public function test_feeds_softdeleted_topic_admin() @@ -716,8 +718,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case 't' => array( array( 'id' => $this->data['topics']['Feeds #1 - Topic #2'], - 'contents_lang' => array('SORRY_AUTH_READ'), + 'contents_lang' => array('SORRY_AUTH_READ_TOPIC'), 'invalid' => true, + 'response_code' => 403, ), ), 'overall' => array( @@ -758,10 +761,10 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case // Test creating a reply $this->login('disapprove_user'); - $post2 = $this->create_post($this->data['forums']['Feeds #1.1'], $post['topic_id'], 'Re: Feeds #1.1 - Topic #2', 'This is a test post posted by the testing framework.', array(), 'POST_STORED_MOD'); + $this->create_post($this->data['forums']['Feeds #1.1'], $post['topic_id'], 'Re: Feeds #1.1 - Topic #2', 'This is a test post posted by the testing framework.', array(), 'POST_STORED_MOD'); $crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Feeds #1.1 - Topic #2']}&sid={$this->sid}"); - $this->assertNotContains('Re: Feeds #1.1 - Topic #2', $crawler->filter('html')->text()); + self::assertNotContains('Re: Feeds #1.1 - Topic #2', $crawler->filter('html')->text()); } public function test_feeds_unapproved_post_admin() @@ -853,7 +856,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $this->data['topics']['Feeds #1 - Topic #3'] = (int) $post['topic_id']; $crawler = self::request('GET', "viewforum.php?f={$this->data['forums']['Feeds #1.1']}&sid={$this->sid}"); - $this->assertNotContains('Feeds #1.1 - Topic #3', $crawler->filter('html')->text()); + self::assertNotContains('Feeds #1.1 - Topic #3', $crawler->filter('html')->text()); $this->logout(); $this->set_flood_interval(15); @@ -869,10 +872,10 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $form = $crawler->selectButton('Submit')->form(); $values = $form->getValues(); - $values["config[flood_interval]"] = $flood_interval; + $values['config[flood_interval]'] = $flood_interval; $form->setValues($values); $crawler = self::submit($form); - $this->assertGreaterThan(0, $crawler->filter('.successbox')->count()); + self::assertGreaterThan(0, $crawler->filter('.successbox')->count()); $this->logout(); } @@ -964,8 +967,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case 't' => array( array( 'id' => $this->data['topics']['Feeds #1.1 - Topic #3'], - 'contents_lang' => array('SORRY_AUTH_READ'), + 'contents_lang' => array('SORRY_AUTH_READ_TOPIC'), 'invalid' => true, + 'response_code' => 403, ), ), 'overall' => array( @@ -1004,7 +1008,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $post = $this->create_topic($this->data['forums']['Feeds #1'], 'Feeds #1 - Topic #3', 'This is a test topic posted by the testing framework. [attachment=0]Attachment #0[/attachment]', array('upload_files' => 1)); $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}"); - $this->assertContains('Feeds #1 - Topic #3', $crawler->filter('html')->text()); + self::assertContains('Feeds #1 - Topic #3', $crawler->filter('html')->text()); $this->data['topics']['Feeds #1 - Topic #3'] = (int) $post['topic_id']; } @@ -1222,7 +1226,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $post2 = $this->create_post($this->data['forums']['Feeds #1'], $this->data['topics']['Feeds #1 - Topic #3'], 'Re: Feeds #1 - Topic #3-1', 'This is a test post posted by the testing framework. [attachment=0]Attachment #0[/attachment]'); $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}"); - $this->assertContains('Re: Feeds #1 - Topic #3-1', $crawler->filter('html')->text()); + self::assertContains('Re: Feeds #1 - Topic #3-1', $crawler->filter('html')->text()); $this->data['posts']['Re: Feeds #1 - Topic #3-1'] = (int) $post2['post_id']; } @@ -1322,9 +1326,14 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case { foreach ($feeds as $feed_data) { - if ($mode === 'f' || $mode === 't') + if ($mode === 'f') + { + $params = "/forum/{$feed_data['id']}"; + $this->assert_feed($params, $feed_data); + } + else if ($mode === 't') { - $params = "?{$mode}={$feed_data['id']}"; + $params = "/topic/{$feed_data['id']}"; $this->assert_feed($params, $feed_data); } else @@ -1348,10 +1357,10 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case case 'news': break; default: - $this->fail('Unsupported feed mode: ' . $mode); + self::fail('Unsupported feed mode: ' . $mode); } - $params = "?mode={$mode}"; + $params = "/{$mode}"; $this->assert_feed($params, $feed_data); } } @@ -1360,19 +1369,19 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case protected function assert_feed($params, $data) { - $crawler = self::request('GET', 'feed.php' . $params, array(), false); + $crawler = self::request('GET', 'app.php/feed' . $params, array(), false); if (empty($data['invalid'])) { self::assert_response_xml(); - $this->assertEquals($data['nb_entries'], $crawler->filter('entry')->count(), "Tested feed : 'feed.php{$params}'"); + self::assertEquals($data['nb_entries'], $crawler->filter('entry')->count(), "Tested feed : 'app.php/feed{$params}'"); if (!empty($data['xpath'])) { foreach($data['xpath'] as $xpath => $count_expected) { - $this->assertCount($count_expected, $crawler->filterXPath($xpath), "Tested feed : 'feed.php{$params}', Search for {$xpath}"); + self::assertCount($count_expected, $crawler->filterXPath($xpath), "Tested feed : 'app.php/feed{$params}', Search for {$xpath}"); } } @@ -1381,7 +1390,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case foreach($data['contents'] as $entry_id => $string) { $content = $crawler->filterXPath("//entry[{$entry_id}]/content")->text(); - $this->assertContains($string, $content, "Tested feed : 'feed.php{$params}'"); + self::assertContains($string, $content, "Tested feed : 'app.php/feed{$params}'"); } } @@ -1390,7 +1399,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case foreach($data['contents_lang'] as $entry_id => $string) { $content = $crawler->filterXPath("//entry[{$entry_id}]/content")->text(); - $this->assertContainsLang($string, $content, "Tested feed : 'feed.php{$params}'"); + self::assertContainsLang($string, $content, "Tested feed : 'app.php/feed{$params}'"); } } @@ -1398,21 +1407,21 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case { foreach($data['attachments'] as $entry_id => $attachments) { + $content = $crawler->filterXPath("//entry[{$entry_id}]/content")->text(); foreach ($attachments as $i => $attachment) { - $content = $crawler->filterXPath("//entry[{$entry_id}]/content")->text(); $url = self::$root_url . "download/file.php?id={$attachment['id']}"; $string = "Attachment #{$i}"; if ($attachment['displayed']) { - $this->assertContains($url, $content, "Tested feed : 'feed.php{$params}'"); - $this->assertNotContains($string, $content, "Tested feed : 'feed.php{$params}'"); + self::assertContains($url, $content, "Tested feed : 'app.php/feed{$params}'"); + self::assertNotContains($string, $content, "Tested feed : 'app.php/feed{$params}'"); } else { - $this->assertContains($string, $content, "Tested feed : 'feed.php{$params}'"); - $this->assertNotContains($url, $content, "Tested feed : 'feed.php{$params}'"); + self::assertContains($string, $content, "Tested feed : 'app.php/feed{$params}'"); + self::assertNotContains($url, $content, "Tested feed : 'app.php/feed{$params}'"); } } } @@ -1420,14 +1429,14 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case } else { - self::assert_response_html(); + self::assert_response_html($data['response_code'] ?: 202); if (!empty($data['contents_lang'])) { + $content = $crawler->filter('html')->text(); foreach($data['contents_lang'] as $string) { - $content = $crawler->filter('html')->text(); - $this->assertContainsLang($string, $content, "Tested feed : 'feed.php{$params}'"); + self::assertContainsLang($string, $content, "Tested feed : 'app.php/feed{$params}'"); } } } @@ -1445,7 +1454,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { - if (in_array($row['forum_name'], $data['forums'])) + if (in_array($row['forum_name'], $data['forums'], false)) { $this->data['forums'][$row['forum_name']] = (int) $row['forum_id']; } @@ -1461,7 +1470,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { - if (in_array($row['topic_title'], $data['topics'])) + if (in_array($row['topic_title'], $data['topics'], false)) { $this->data['topics'][$row['topic_title']] = (int) $row['topic_id']; } @@ -1478,7 +1487,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { - if (in_array($row['post_subject'], $data['posts'])) + if (in_array($row['post_subject'], $data['posts'], false)) { $this->data['posts'][$row['post_subject']] = (int) $row['post_id']; $post_ids[] = (int) $row['post_id']; diff --git a/tests/functional/fileupload_remote_test.php b/tests/functional/fileupload_remote_test.php index 6ece150b23..b70d49cddd 100644 --- a/tests/functional/fileupload_remote_test.php +++ b/tests/functional/fileupload_remote_test.php @@ -11,13 +11,29 @@ * */ -require_once __DIR__ . '/../../phpBB/includes/functions_upload.php'; - /** * @group functional */ class phpbb_functional_fileupload_remote_test extends phpbb_functional_test_case { + /** @var \phpbb\filesystem\filesystem_interface */ + protected $filesystem; + + /** @var \phpbb\files\factory */ + protected $factory; + + /** @var \bantu\IniGetWrapper\IniGetWrapper */ + protected $php_ini; + + /** @var \phpbb\language\language */ + protected $language; + + /** @var \phpbb\request\request_interface */ + protected $request; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + public function setUp() { parent::setUp(); @@ -25,19 +41,28 @@ class phpbb_functional_fileupload_remote_test extends phpbb_functional_test_case // URL // Global $config required by unique_id - // Global $user required by fileupload::remote_upload - global $config, $user; + global $config, $phpbb_root_path, $phpEx; if (!is_array($config)) { - $config = array(); + $config = new \phpbb\config\config(array()); } $config['rand_seed'] = ''; $config['rand_seed_last_update'] = time() + 600; + $config['remote_upload_verify'] = 0; + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $this->request = $this->getMock('\phpbb\request\request'); + $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper; - $user = new phpbb_mock_user(); - $user->lang = new phpbb_mock_lang(); + $container = new phpbb_mock_container_builder(); + $container->set('files.filespec', new \phpbb\files\filespec($this->filesystem, $this->language, $this->php_ini, new \FastImageSize\FastImageSize(), $this->phpbb_root_path)); + $this->factory = new \phpbb\files\factory($container); + $container->set('files.factory', $this->factory); + $container->set('files.types.remote', new \phpbb\files\types\remote($config, $this->factory, $this->language, $this->php_ini, $this->request, $phpbb_root_path)); + $this->phpbb_root_path = $phpbb_root_path; } public function tearDown() @@ -49,30 +74,47 @@ class phpbb_functional_fileupload_remote_test extends phpbb_functional_test_case public function test_invalid_extension() { - $upload = new fileupload('', array('jpg'), 100); - $file = $upload->remote_upload(self::$root_url . 'develop/blank.gif'); + /** @var \phpbb\files\upload $upload */ + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_error_prefix('') + ->set_allowed_extensions(array('jpg')) + ->set_max_filesize(100); + $file = $upload->handle_upload('files.types.remote', self::$root_url . 'develop/blank.gif'); $this->assertEquals('URL_INVALID', $file->error[0]); } public function test_empty_file() { - $upload = new fileupload('', array('jpg'), 100); - $file = $upload->remote_upload(self::$root_url . 'develop/blank.jpg'); + /** @var \phpbb\files\upload $upload */ + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_error_prefix('') + ->set_allowed_extensions(array('jpg')) + ->set_max_filesize(100); + $file = $upload->handle_upload('files.types.remote', self::$root_url . 'develop/blank.jpg'); $this->assertEquals('EMPTY_REMOTE_DATA', $file->error[0]); } public function test_successful_upload() { - $upload = new fileupload('', array('gif'), 1000); - $file = $upload->remote_upload(self::$root_url . 'styles/prosilver/theme/images/forum_read.gif'); + /** @var \phpbb\files\upload $upload */ + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_error_prefix('') + ->set_allowed_extensions(array('gif')) + ->set_max_filesize(1000); + $file = $upload->handle_upload('files.types.remote', self::$root_url . 'styles/prosilver/theme/images/forum_read.gif'); $this->assertEquals(0, sizeof($file->error)); - $this->assertTrue(file_exists($file->filename)); + $this->assertTrue(file_exists($file->get('filename'))); + $this->assertTrue($file->is_uploaded()); } public function test_too_large() { - $upload = new fileupload('', array('gif'), 100); - $file = $upload->remote_upload(self::$root_url . 'styles/prosilver/theme/images/forum_read.gif'); + /** @var \phpbb\files\upload $upload */ + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_error_prefix('') + ->set_allowed_extensions(array('gif')) + ->set_max_filesize(100); + $file = $upload->handle_upload('files.types.remote', self::$root_url . 'styles/prosilver/theme/images/forum_read.gif'); $this->assertEquals(1, sizeof($file->error)); $this->assertEquals('WRONG_FILESIZE', $file->error[0]); } diff --git a/tests/functional/fixtures/ext/foo/bar/acp/main_info.php b/tests/functional/fixtures/ext/foo/bar/acp/main_info.php index ec378e0e75..371ab7c967 100644 --- a/tests/functional/fixtures/ext/foo/bar/acp/main_info.php +++ b/tests/functional/fixtures/ext/foo/bar/acp/main_info.php @@ -28,7 +28,6 @@ class main_info return array( 'filename' => 'foo\bar\acp\main_module', 'title' => 'ACP_FOOBAR_TITLE', - 'version' => '1.0.0', 'modes' => array( 'mode' => array('title' => 'ACP_FOOBAR_MODE', 'auth' => '', 'cat' => array('ACP_FOOBAR_TITLE')), ), diff --git a/tests/functional/fixtures/ext/foo/bar/ucp/main_info.php b/tests/functional/fixtures/ext/foo/bar/ucp/main_info.php index d34244f800..4c74442639 100644 --- a/tests/functional/fixtures/ext/foo/bar/ucp/main_info.php +++ b/tests/functional/fixtures/ext/foo/bar/ucp/main_info.php @@ -20,7 +20,6 @@ class main_info return array( 'filename' => '\foo\bar\ucp\main_module', 'title' => 'ACP_FOOBAR_TITLE', - 'version' => '1.0.0', 'modes' => array( 'mode' => array('title' => 'ACP_FOOBAR_MODE', 'auth' => '', 'cat' => array('ACP_FOOBAR_TITLE')), ), diff --git a/tests/functional/forum_style_test.php b/tests/functional/forum_style_test.php index 65be94f4d0..b3c1115b7f 100644 --- a/tests/functional/forum_style_test.php +++ b/tests/functional/forum_style_test.php @@ -16,16 +16,28 @@ */ class phpbb_functional_forum_style_test extends phpbb_functional_test_case { + public function test_font_awesome_style() + { + $crawler = self::request('GET', 'viewtopic.php?t=1&f=2'); + $this->assertContains('font-awesome.min', $crawler->filter('head > link[rel=stylesheet]')->eq(0)->attr('href')); + + $crawler = self::request('GET', 'viewtopic.php?t=1'); + $this->assertContains('font-awesome.min', $crawler->filter('head > link[rel=stylesheet]')->eq(0)->attr('href')); + + $crawler = self::request('GET', 'viewtopic.php?t=1&view=next'); + $this->assertContains('font-awesome.min', $crawler->filter('head > link[rel=stylesheet]')->eq(0)->attr('href')); + } + public function test_default_forum_style() { $crawler = self::request('GET', 'viewtopic.php?t=1&f=2'); - $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->attr('href')); + $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href')); $crawler = self::request('GET', 'viewtopic.php?t=1'); - $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->attr('href')); + $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href')); $crawler = self::request('GET', 'viewtopic.php?t=1&view=next'); - $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->attr('href')); + $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href')); } public function test_custom_forum_style() @@ -35,13 +47,13 @@ class phpbb_functional_forum_style_test extends phpbb_functional_test_case $db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET forum_style = 2 WHERE forum_id = 2'); $crawler = self::request('GET', 'viewtopic.php?t=1&f=2'); - $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->attr('href')); + $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href')); $crawler = self::request('GET', 'viewtopic.php?t=1'); - $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->attr('href')); + $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href')); $crawler = self::request('GET', 'viewtopic.php?t=1&view=next'); - $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->attr('href')); + $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href')); $db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET forum_style = 0 WHERE forum_id = 2'); $this->delete_style(2, 'test_style'); diff --git a/tests/functional/notification_test.php b/tests/functional/notification_test.php index ec03f7a6a4..87c36dd4d1 100644 --- a/tests/functional/notification_test.php +++ b/tests/functional/notification_test.php @@ -11,6 +11,8 @@ * */ +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + /** * @group functional */ @@ -21,15 +23,15 @@ class phpbb_functional_notification_test extends phpbb_functional_test_case return array( // Rows inserted by phpBB/install/schemas/schema_data.sql // Also see PHPBB3-11460 - array('notification.type.post_notification', true), - array('notification.type.topic_notification', true), + array('notification.type.post_notification.method.board', true), + array('notification.type.topic_notification.method.board', true), array('notification.type.post_notification.method.email', true), array('notification.type.topic_notification.method.email', true), // Default behaviour for in-board notifications: // If user did not opt-out, in-board notifications are on. - array('notification.type.bookmark_notification', true), - array('notification.type.quote_notification', true), + array('notification.type.bookmark_notification.method.board', true), + array('notification.type.quote_notification.method.board', true), // Default behaviour for email notifications: // If user did not opt-in, email notifications are off. diff --git a/tests/functional/permission_roles_test.php b/tests/functional/permission_roles_test.php new file mode 100644 index 0000000000..82d5be68c3 --- /dev/null +++ b/tests/functional/permission_roles_test.php @@ -0,0 +1,86 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once __DIR__ . '/../../phpBB/includes/functions.php'; + +/** +* @group functional +*/ +class functional_permission_roles_test extends phpbb_functional_test_case +{ + public function data_permission_roles() + { + return array( + array( + array(0, 14), + array(17, 17), + array( + 'role[5][1]' => 14, + ) + ), + array( + array(14, 14), + array(17, 17), + array( + 'role[5][1]' => 0, + ) + ), + array( + array(0, 14), + array(17, 17) + ), + ); + } + /** + * @dataProvider data_permission_roles + */ + public function test_permission_roles($admin_roles, $guest_roles, $set_values = array()) + { + $this->login(); + $this->admin_login(); + $this->add_lang('acp/permissions'); + $crawler = self::request('GET', 'adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid); + + // Select forums + $form = $crawler->filter('form[id=select_victim]')->form(); + $form['forum_id']->setValue(array(1,2)); + $crawler = self::$client->submit($form); + + // Select administrators and guests + $groups_form = $crawler->filter('form[id=groups]')->form(); + $groups_form['group_id']->setValue(array(1,5)); + + $crawler = self::submit($groups_form); + $form = $crawler->filter('form')->form(); + $values = $form->getValues(); + + // Check default settings + $this->assertEquals($admin_roles[0], $values['role[5][1]']); + $this->assertEquals($admin_roles[1], $values['role[5][2]']); + $this->assertEquals($guest_roles[0], $values['role[1][1]']); + $this->assertEquals($guest_roles[1], $values['role[1][2]']); + + // Set admin to full access on category + foreach ($set_values as $key => $value) + { + $form[$key]->setValue($value); + } + + $form_values = $form->getValues(); + $form_values['action[apply_all_permissions]'] = true; + $crawler = self::request('POST', 'adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid, $form_values); + $this->assertContainsLang('AUTH_UPDATED', $crawler->text()); + + $this->logout(); + } +} diff --git a/tests/functional/plupload_test.php b/tests/functional/plupload_test.php index d358681ad1..9d284a7e57 100644 --- a/tests/functional/plupload_test.php +++ b/tests/functional/plupload_test.php @@ -107,11 +107,11 @@ class phpbb_functional_plupload_test extends phpbb_functional_test_case if ($i < self::CHUNKS - 1) { - $this->assertContains('{"jsonrpc":"2.0","id":"id","result":null}', self::$client->getResponse()->getContent()); + $this->assertContains('{"jsonrpc":"2.0","id":"id","result":null}', self::get_content()); } else { - $response = json_decode(self::$client->getResponse()->getContent(), true); + $response = json_decode(self::get_content(), true); $this->assertEquals('valid.jpg', $response['data'][0]['real_filename']); } @@ -134,7 +134,8 @@ class phpbb_functional_plupload_test extends phpbb_functional_test_case 'error' => UPLOAD_ERR_OK, ); - $crawler = self::$client->request( + self::$client->setServerParameter('HTTP_X_PHPBB_USING_PLUPLOAD', '1'); + self::$client->request( 'POST', $url . '&sid=' . $this->sid, array( @@ -144,11 +145,10 @@ class phpbb_functional_plupload_test extends phpbb_functional_test_case 'real_filename' => 'valid.jpg', 'add_file' => $this->lang('ADD_FILE'), ), - array('fileupload' => $file), - array('X-PHPBB-USING-PLUPLOAD' => '1') + array('fileupload' => $file) ); - $response = json_decode(self::$client->getResponse()->getContent(), true); + $response = json_decode(self::get_content(), true); $this->assertEquals('valid.jpg', $response['data'][0]['real_filename']); } } diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index 33632a01e1..bf9e3eb51a 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -45,14 +45,6 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case self::create_post(2, 1, - 'Unsupported characters', - "This is a test with these weird characters: \xF0\x9F\x88\xB3 \xF0\x9F\x9A\xB6", - array(), - 'Your message contains the following unsupported characters' - ); - - self::create_post(2, - 1, "Unsupported: \xF0\x9F\x88\xB3 \xF0\x9F\x9A\xB6", 'This is a test with emoji characters in the topic title.', array(), @@ -60,6 +52,40 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case ); } + public function test_supported_unicode_characters() + { + $this->login(); + + $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.'); + $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', "This is a test with these weird characters: \xF0\x9F\x84\x90 \xF0\x9F\x84\x91"); + $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}"); + $this->assertContains("\xF0\x9F\x84\x90 \xF0\x9F\x84\x91", $crawler->text()); + } + + public function test_html_entities() + { + $this->login(); + + $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.'); + $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', '😀'); + $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}"); + $this->assertContains('😀', $crawler->text()); + } + + public function test_quote() + { + $text = 'Test post </textarea>"\' &&amp;'; + $expected = "(\\[quote=admin[^\\]]*\\]\n" . preg_quote($text) . "\n\\[/quote\\])"; + + $this->login(); + $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic'); + $post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text); + + $crawler = self::request('GET', "posting.php?mode=quote&f=2&t={$post['topic_id']}&p={$post['post_id']}&sid={$this->sid}"); + + $this->assertRegexp($expected, $crawler->filter('textarea#message')->text()); + } + /** * @testdox max_quote_depth is applied to the text populating the posting form */ @@ -67,10 +93,10 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case { $text = '0[quote]1[quote]2[/quote]1[/quote]0'; $expected = array( - 0 => '[quote="admin"]0[quote]1[quote]2[/quote]1[/quote]0[/quote]', - 1 => '[quote="admin"]00[/quote]', - 2 => '[quote="admin"]0[quote]11[/quote]0[/quote]', - 3 => '[quote="admin"]0[quote]1[quote]2[/quote]1[/quote]0[/quote]', + 0 => '0[quote]1[quote]2[/quote]1[/quote]0', + 1 => '00', + 2 => '0[quote]11[/quote]0', + 3 => '0[quote]1[quote]2[/quote]1[/quote]0', ); $this->login(); @@ -83,7 +109,10 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case { $this->set_quote_depth($quote_depth); $crawler = self::request('GET', $quote_url); - $this->assertContains($expected_text, $crawler->filter('textarea#message')->text()); + $this->assertRegexp( + "(\\[quote=admin[^\\]]*\\]\n?" . preg_quote($expected_text) . "\n?\\[/quote\\])", + $crawler->filter('textarea#message')->text() + ); } } @@ -140,4 +169,65 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case $crawler = self::submit($form); $this->assertEquals(1, $crawler->filter('.successbox')->count()); } + + public function test_ticket_8420() + { + $text = '[b][url=http://example.org] :arrow: here[/url][/b]'; + + $this->login(); + $crawler = self::request('GET', 'posting.php?mode=post&f=2'); + $form = $crawler->selectButton('Preview')->form(array( + 'subject' => 'Test subject', + 'message' => $text + )); + $crawler = self::submit($form); + $this->assertEquals($text, $crawler->filter('#message')->text()); + } + + public function test_old_signature_in_preview() + { + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_sig = '[b:2u8sdcwb]My signature[/b:2u8sdcwb]', + user_sig_bbcode_uid = '2u8sdcwb', + user_sig_bbcode_bitfield = 'QA==' + WHERE user_id = 2"; + $this->get_db()->sql_query($sql); + + $this->login(); + $crawler = self::request('GET', 'posting.php?mode=post&f=2'); + $form = $crawler->selectButton('Preview')->form(array( + 'subject' => 'Test subject', + 'message' => 'My post', + )); + $crawler = self::submit($form); + $this->assertContains( + '<span style="font-weight: bold">My signature</span>', + $crawler->filter('#preview .signature')->html() + ); + } + + /** + * @ticket PHPBB3-10628 + */ + public function test_www_links_preview() + { + $text = 'www.example.org'; + $url = 'http://' . $text; + + $this->add_lang('posting'); + $this->login(); + + $crawler = self::request('GET', 'posting.php?mode=post&f=2'); + $form = $crawler->selectButton('Preview')->form(array( + 'subject' => 'Test subject', + 'message' => $text + )); + $crawler = self::submit($form); + + // Test that the textarea remains unchanged + $this->assertEquals($text, $crawler->filter('#message')->text()); + + // Test that the preview contains the correct link + $this->assertEquals($url, $crawler->filter('#preview a')->attr('href')); + } } diff --git a/tests/functional/private_messages_test.php b/tests/functional/private_messages_test.php index 1f6dc3a979..7fda26fb49 100644 --- a/tests/functional/private_messages_test.php +++ b/tests/functional/private_messages_test.php @@ -66,4 +66,45 @@ class phpbb_functional_private_messages_test extends phpbb_functional_test_case $crawler = self::submit($form); $this->assertContains($this->lang('CONFIG_UPDATED'), $crawler->filter('.successbox')->text()); } + + public function test_quote_post() + { + $text = 'Test post'; + + $this->login(); + $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic'); + $post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text); + + $expected = '(\\[quote=admin post_id=' . $post['post_id'] . ' time=\\d+ user_id=2\\]' . $text . '\\[/quote\\])'; + + $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=quotepost&p=' . $post['post_id'] . '&sid=' . $this->sid); + + $this->assertRegexp($expected, $crawler->filter('textarea#message')->text()); + } + + public function test_quote_pm() + { + $text = 'This is a test private message sent by the testing framework.'; + $expected = "(\\[quote=admin time=\\d+ user_id=2\\]\n" . $text . "\n\\[/quote\\])"; + + $this->login(); + $message_id = $this->create_private_message('Test', $text, array(2)); + + $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=quote&p=' . $message_id . '&sid=' . $this->sid); + + $this->assertRegexp($expected, $crawler->filter('textarea#message')->text()); + } + + public function test_quote_forward() + { + $text = 'This is a test private message sent by the testing framework.'; + $expected = "[quote=admin]\n" . $text . "\n[/quote]"; + + $this->login(); + $message_id = $this->create_private_message('Test', $text, array(2)); + + $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=forward&f=0&p=' . $message_id . '&sid=' . $this->sid); + + $this->assertContains($expected, $crawler->filter('textarea#message')->text()); + } } diff --git a/tests/functional/report_post_captcha_test.php b/tests/functional/report_post_captcha_test.php index 93a03bd931..36a1a9ee4d 100644 --- a/tests/functional/report_post_captcha_test.php +++ b/tests/functional/report_post_captcha_test.php @@ -18,12 +18,13 @@ class phpbb_functional_report_post_captcha_test extends phpbb_functional_test_ca { public function test_guest_report_post() { - $crawler = self::request('GET', 'report.php?f=2&p=1'); + $crawler = self::request('GET', 'app.php/post/1/report', array(), false); + $this->assert_response_html(403); $this->add_lang('mcp'); $this->assertContains($this->lang('USER_CANNOT_REPORT'), $crawler->filter('html')->text()); $this->set_reporting_guest(1); - $crawler = self::request('GET', 'report.php?f=2&p=1'); + $crawler = self::request('GET', 'app.php/post/1/report'); $this->assertContains($this->lang('CONFIRM_CODE'), $crawler->filter('html')->text()); $this->set_reporting_guest(-1); } @@ -31,7 +32,7 @@ class phpbb_functional_report_post_captcha_test extends phpbb_functional_test_ca public function test_user_report_post() { $this->login(); - $crawler = self::request('GET', 'report.php?f=2&p=1'); + $crawler = self::request('GET', 'app.php/post/1/report'); $this->assertNotContains($this->lang('CONFIRM_CODE'), $crawler->filter('html')->text()); $this->add_lang('mcp'); diff --git a/tests/functional/search/base.php b/tests/functional/search/base.php index 1d37d748df..a3cac381d2 100644 --- a/tests/functional/search/base.php +++ b/tests/functional/search/base.php @@ -36,6 +36,8 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case $this->login(); $this->admin_login(); + $this->create_search_index('\phpbb\search\fulltext_native'); + $post = $this->create_topic(2, 'Test Topic 1 foosubject', 'This is a test topic posted by the barsearch testing framework.'); $crawler = self::request('GET', 'adm/index.php?i=acp_search&mode=settings&sid=' . $this->sid); @@ -58,6 +60,7 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case $this->delete_topic($post['topic_id']); $this->markTestSkipped("Search backend is not supported/running"); } + $this->create_search_index(); } @@ -72,14 +75,14 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case $this->delete_topic($post['topic_id']); } - protected function create_search_index() + protected function create_search_index($backend = null) { $this->add_lang('acp/search'); $crawler = self::request( 'POST', 'adm/index.php?i=acp_search&mode=index&sid=' . $this->sid, array( - 'search_type' => $this->search_backend, + 'search_type' => ( ($backend === null) ? $this->search_backend : $backend ), 'action' => 'create', 'submit' => true, ) diff --git a/tests/functions/build_url_test.php b/tests/functions/build_url_test.php index a59b94c744..3e19b51f02 100644 --- a/tests/functions/build_url_test.php +++ b/tests/functions/build_url_test.php @@ -29,7 +29,7 @@ class phpbb_build_url_test extends phpbb_test_case new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + new \phpbb\filesystem\filesystem(), $this->getMock('\phpbb\request\request'), $phpbb_root_path, 'php' diff --git a/tests/functions/generate_string_list.php b/tests/functions/generate_string_list.php index cd1e37618a..bcf0c09fe4 100644 --- a/tests/functions/generate_string_list.php +++ b/tests/functions/generate_string_list.php @@ -22,7 +22,12 @@ class phpbb_generate_string_list_test extends phpbb_test_case { parent::setUp(); - $this->user = new \phpbb\user('\phpbb\datetime'); + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $this->user = $user; $this->user->data = array('user_lang' => 'en'); $this->user->add_lang('common'); } @@ -36,7 +41,7 @@ class phpbb_generate_string_list_test extends phpbb_test_case ), array( array('A'), - 'A', + 'A', ), array( array(2 => 'A', 3 => 'B'), diff --git a/tests/functions/get_remote_file_test.php b/tests/functions/get_remote_file_test.php index 612d82273e..781a73a462 100644 --- a/tests/functions/get_remote_file_test.php +++ b/tests/functions/get_remote_file_test.php @@ -12,7 +12,7 @@ */ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; -require_once dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_compatibility.php'; /** * @group slow diff --git a/tests/functions/user_delete_test.php b/tests/functions/user_delete_test.php index db52dcded7..bd6b53c59f 100644 --- a/tests/functions/user_delete_test.php +++ b/tests/functions/user_delete_test.php @@ -28,10 +28,12 @@ class phpbb_functions_user_delete_test extends phpbb_database_test_case { parent::setUp(); - global $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $user; + global $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $user, $phpbb_root_path, $phpEx; $this->db = $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $phpbb_container = new phpbb_mock_container_builder(); $config = new \phpbb\config\config(array( @@ -39,8 +41,7 @@ class phpbb_functions_user_delete_test extends phpbb_database_test_case 'auth_oauth_google_key' => 'foo', 'auth_oauth_google_secret' => 'bar', )); - set_config_count('foobar', 0, false, $config); - $cache = new \phpbb\cache\driver\null(); + $cache = new \phpbb\cache\driver\dummy(); $request = new phpbb_mock_request(); $notification_manager = new phpbb_mock_notification_manager(); $provider_collection = new \phpbb\auth\provider_collection($phpbb_container, $config); @@ -67,6 +68,7 @@ class phpbb_functions_user_delete_test extends phpbb_database_test_case $request, $user, 'phpbb_oauth_tokens', + 'phpbb_oauth_states', 'phpbb_oauth_accounts', $oauth_provider_collection, 'phpbb_users', diff --git a/tests/functions_install/ignore_new_file_on_update_test.php b/tests/functions_install/ignore_new_file_on_update_test.php deleted file mode 100644 index 822c5e6789..0000000000 --- a/tests/functions_install/ignore_new_file_on_update_test.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -require_once dirname(__FILE__) . '/../../phpBB/includes/functions_install.php'; - -class phpbb_functions_install_ignore_new_file_on_update_test extends phpbb_test_case -{ - static public function ignore_new_file_on_update_data() - { - return array( - array('willneverexist.php', false), - array('includes/dirwillneverexist/newfile.php', false), - - array('language/en/email/short/bookmark.txt', false), - array('language/languagewillneverexist/email/short/bookmark.txt', true), - - array('styles/prosilver/template/bbcode.html', false), - array('styles/stylewillneverexist/template/bbcode.html', true), - - array('styles/prosilver/theme/en/icon_user_online.gif', false), - array('styles/prosilver/theme/languagewillneverexist/icon_user_online.gif', true), - - array('styles/prosilver/theme/imageset.css', false), - ); - } - - /** - * @dataProvider ignore_new_file_on_update_data - */ - public function test_ignore_new_file_on_update($file, $expected) - { - global $phpbb_root_path; - $this->assertEquals($expected, phpbb_ignore_new_file_on_update($phpbb_root_path, $file)); - } -} diff --git a/tests/functions_privmsgs/fixtures/get_max_setting_from_group.xml b/tests/functions_privmsgs/fixtures/get_max_setting_from_group.xml new file mode 100644 index 0000000000..c78d63f7cb --- /dev/null +++ b/tests/functions_privmsgs/fixtures/get_max_setting_from_group.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_groups"> + <column>group_id</column> + <column>group_desc</column> + <column>group_message_limit</column> + <column>group_max_recipients</column> + <row> + <value>1</value> + <value></value> + <value>1</value> + <value>3</value> + </row> + <row> + <value>2</value> + <value></value> + <value>2</value> + <value>4</value> + </row> + <row> + <value>3</value> + <value></value> + <value>0</value> + <value>0</value> + </row> + <row> + <value>4</value> + <value></value> + <value>0</value> + <value>5</value> + </row> + </table> + <table name="phpbb_user_group"> + <column>user_id</column> + <column>group_id</column> + <column>user_pending</column> + <row> + <value>1</value> + <value>1</value> + <value>0</value> + </row> + <row> + <value>1</value> + <value>2</value> + <value>0</value> + </row> + <row> + <value>1</value> + <value>3</value> + <value>0</value> + </row> + <row> + <value>2</value> + <value>1</value> + <value>0</value> + </row> + <row> + <value>2</value> + <value>2</value> + <value>0</value> + </row> + <row> + <value>3</value> + <value>3</value> + <value>0</value> + </row> + <row> + <value>4</value> + <value>4</value> + <value>0</value> + </row> + <row> + <value>5</value> + <value>3</value> + <value>1</value> + </row> + <row> + <value>5</value> + <value>2</value> + <value>0</value> + </row> + </table> +</dataset> diff --git a/tests/functions_privmsgs/get_max_setting_from_group_test.php b/tests/functions_privmsgs/get_max_setting_from_group_test.php new file mode 100644 index 0000000000..3eb7866802 --- /dev/null +++ b/tests/functions_privmsgs/get_max_setting_from_group_test.php @@ -0,0 +1,64 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_privmsgs.php'; + +class phpbb_functions_privmsgs_get_max_setting_from_group_test extends phpbb_database_test_case +{ + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/get_max_setting_from_group.xml'); + } + + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + protected function setUp() + { + parent::setUp(); + + $this->db = $this->new_dbal(); + } + + static public function get_max_setting_from_group_data() + { + return array( + array(1, 0, 'message_limit'), + array(2, 2, 'message_limit'), + array(3, 0, 'message_limit'), + array(4, 0, 'message_limit'), + array(5, 2, 'message_limit'), + array(1, 0, 'max_recipients'), + array(2, 4, 'max_recipients'), + array(3, 0, 'max_recipients'), + array(4, 5, 'max_recipients'), + array(5, 4, 'max_recipients'), + ); + } + + /** + * @dataProvider get_max_setting_from_group_data + */ + public function test_get_max_setting_from_group($user_id, $expected, $setting) + { + $this->assertEquals($expected, phpbb_get_max_setting_from_group($this->db, $user_id, $setting)); + } + + /** + * @expectedException InvalidArgumentException + */ + public function test_get_max_setting_from_group_throws() + { + phpbb_get_max_setting_from_group($this->db, ANONYMOUS, 'not_a_setting'); + } +} diff --git a/tests/functions_user/delete_user_test.php b/tests/functions_user/delete_user_test.php index 7db69e332c..6d2e1fa20a 100644 --- a/tests/functions_user/delete_user_test.php +++ b/tests/functions_user/delete_user_test.php @@ -25,19 +25,19 @@ class phpbb_functions_user_delete_user_test extends phpbb_database_test_case { parent::setUp(); - global $cache, $config, $db, $phpbb_dispatcher, $phpbb_container; + global $cache, $config, $db, $phpbb_dispatcher, $phpbb_container, $phpbb_root_path; $db = $this->db = $this->new_dbal(); $config = new \phpbb\config\config(array( 'load_online_time' => 5, 'search_type' => '\phpbb\search\fulltext_mysql', )); - set_config(false, false, false, $config); - set_config_count(false, false, false, $config); $cache = new phpbb_mock_null_cache(); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $phpbb_container = new phpbb_mock_container_builder(); $phpbb_container->set('notification_manager', new phpbb_mock_notification_manager()); + // Works as a workaround for tests + $phpbb_container->set('attachment.manager', new \phpbb\attachment\delete($config, $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path)); $phpbb_container->set( 'auth.provider.db', new phpbb_mock_auth_provider() diff --git a/tests/functions_user/group_user_attributes_test.php b/tests/functions_user/group_user_attributes_test.php index 99a15b32bf..6ccada44f8 100644 --- a/tests/functions_user/group_user_attributes_test.php +++ b/tests/functions_user/group_user_attributes_test.php @@ -139,7 +139,7 @@ class phpbb_functions_user_group_user_attributes_test extends phpbb_database_tes $auth = $this->getMock('\phpbb\auth\auth'); $auth->expects($this->any()) ->method('acl_clear_prefetch'); - $cache_driver = new \phpbb\cache\driver\null(); + $cache_driver = new \phpbb\cache\driver\dummy(); $phpbb_container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); $phpbb_container ->expects($this->any()) diff --git a/tests/group/helper_test.php b/tests/group/helper_test.php new file mode 100644 index 0000000000..2377a6f47c --- /dev/null +++ b/tests/group/helper_test.php @@ -0,0 +1,68 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_group_helper_test extends phpbb_test_case +{ + /** @var \phpbb\group\helper */ + protected $group_helper; + + public function setUp() + { + global $phpbb_root_path, $phpEx; + + // Set up language service + $lang = new \phpbb\language\language( + new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx) + ); + + // Set up language data for testing + $reflection_class = new ReflectionClass('\phpbb\language\language'); + + // Set default language files loaded flag to true + $loaded_flag = $reflection_class->getProperty('common_language_files_loaded'); + $loaded_flag->setAccessible(true); + $loaded_flag->setValue($lang, true); + + // Set up test language data + $lang_array = $reflection_class->getProperty('lang'); + $lang_array->setAccessible(true); + $lang_array->setValue($lang, $this->get_test_language_data_set()); + + // Set up group helper + $this->group_helper = new \phpbb\group\helper($lang); + } + + public function test_get_name() + { + // They should be totally fine + $this->assertEquals('Bots', $this->group_helper->get_name('Bots')); + $this->assertEquals('Some new group', $this->group_helper->get_name('new_group')); + $this->assertEquals('Should work', $this->group_helper->get_name('group_with_ümlauts')); + + // This should fail (obviously) + $this->assertNotEquals('They key does not contain uppercase letters', $this->group_helper->get_name('not_uppercase')); + + // The key doesn't exist so just return group name... + $this->assertEquals('Awesome group', $this->group_helper->get_name('Awesome group')); + } + + protected function get_test_language_data_set() + { + return array( + 'G_BOTS' => 'Bots', + 'G_NEW_GROUP' => 'Some new group', + 'G_not_uppercase' => 'The key does not contain uppercase letters', + 'G_GROUP_WITH_ÜMLAUTS' => 'Should work', + ); + } +} diff --git a/tests/groupposition/legend_test.php b/tests/groupposition/legend_test.php index fe003e93a7..566a8a2935 100644 --- a/tests/groupposition/legend_test.php +++ b/tests/groupposition/legend_test.php @@ -33,11 +33,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case */ public function test_get_group_value($group_id, $expected, $throws_exception) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); if ($throws_exception) @@ -51,11 +53,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case public function test_get_group_count() { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\legend($db, $user); @@ -91,11 +95,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case */ public function test_add_group($group_id, $expected_added, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\legend($db, $user); @@ -179,11 +185,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case */ public function test_delete_group($group_id, $skip_group, $expected_deleted, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\legend($db, $user); @@ -234,11 +242,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case */ public function test_move_up($group_id, $excepted_moved, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\legend($db, $user); @@ -289,11 +299,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case */ public function test_move_down($group_id, $excepted_moved, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\legend($db, $user); @@ -387,11 +399,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case */ public function test_move($group_id, $increment, $excepted_moved, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\legend($db, $user); diff --git a/tests/groupposition/teampage_test.php b/tests/groupposition/teampage_test.php index 1e61e3ebfb..dff52f7a43 100644 --- a/tests/groupposition/teampage_test.php +++ b/tests/groupposition/teampage_test.php @@ -35,11 +35,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case */ public function test_get_group_value($group_id, $expected, $throws_exception) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); if ($throws_exception) @@ -53,11 +55,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case public function test_get_group_count() { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\teampage($db, $user, $cache); @@ -137,11 +141,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case */ public function test_add_group_teampage($group_id, $parent_id, $expected_added, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\teampage($db, $user, $cache); @@ -180,11 +186,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case */ public function test_add_category_teampage($group_name, $expected_added, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\teampage($db, $user, $cache); @@ -247,11 +255,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case */ public function test_delete_group($group_id, $expected_deleted, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\teampage($db, $user, $cache); @@ -299,11 +309,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case */ public function test_delete_teampage($teampage_id, $expected_deleted, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\teampage($db, $user, $cache); @@ -462,11 +474,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case */ public function test_move($group_id, $move_delta, $excepted_moved, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\teampage($db, $user, $cache); @@ -625,11 +639,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case */ public function test_move_teampage($teampage_id, $move_delta, $excepted_moved, $expected) { - global $cache; + global $cache, $phpbb_root_path, $phpEx; $cache = new phpbb_mock_cache; $db = $this->new_dbal(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = array(); $test_class = new \phpbb\groupposition\teampage($db, $user, $cache); diff --git a/tests/help/manager_test.php b/tests/help/manager_test.php new file mode 100644 index 0000000000..68534d9a32 --- /dev/null +++ b/tests/help/manager_test.php @@ -0,0 +1,184 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_help_manager_test extends phpbb_test_case +{ + /** @var \phpbb\help\manager */ + protected $manager; + /** @var \phpbb\template\template */ + protected $template; + /** @var \phpbb\language\language */ + protected $language; + + public function setUp() + { + $this->template = $this->getMockBuilder('\phpbb\template\template') + ->disableOriginalConstructor() + ->getMock(); + $this->language = $this->getMockBuilder('\phpbb\language\language') + ->disableOriginalConstructor() + ->getMock(); + + $this->manager = new \phpbb\help\manager( + new \phpbb_mock_event_dispatcher(), + $this->language, + $this->template + ); + } + + public function add_block_data() + { + return array( + array('abc', false, array(), false), + array('def', true, array(), true), + array( + 'abc', + false, + array( + 'question1' => 'answer1', + 'question2' => 'answer2', + 'question3' => 'answer3', + ), + false + ), + ); + } + + /** + * @dataProvider add_block_data + * + * @param string $block_name + * @param bool $switch + * @param array $questions + * @param bool $switch_expected + */ + public function test_add_block($block_name, $switch, $questions, $switch_expected) + { + $this->language->expects($this->at(0)) + ->method('lang') + ->with($block_name) + ->willReturn(strtoupper($block_name)); + $lang_call_count = 1; + foreach ($questions as $question => $answer) + { + $this->language->expects($this->at($lang_call_count)) + ->method('lang') + ->with($question) + ->willReturn(strtoupper($question)); + $lang_call_count++; + + $this->language->expects($this->at($lang_call_count)) + ->method('lang') + ->with($answer) + ->willReturn(strtoupper($answer)); + $lang_call_count++; + } + + $this->template->expects($this->at(0)) + ->method('assign_block_vars') + ->with('faq_block', array( + 'BLOCK_TITLE' => strtoupper($block_name), + 'SWITCH_COLUMN' => $switch_expected, + )); + $template_call_count = 1; + foreach ($questions as $question => $answer) + { + $this->template->expects($this->at($template_call_count)) + ->method('assign_block_vars') + ->with('faq_block.faq_row', array( + 'FAQ_QUESTION' => strtoupper($question), + 'FAQ_ANSWER' => strtoupper($answer), + )); + $template_call_count++; + } + + $this->manager->add_block($block_name, $switch, $questions); + + $this->assertEquals($switch_expected, $this->manager->switched_column()); + } + + public function add_question_data() + { + return array( + array('abc', false, false), + array('def', true, true), + ); + } + + /** + * @dataProvider add_question_data + * + * @param string $question + * @param string $answer + */ + public function test_add_question($question, $answer) + { + $this->language->expects($this->at(0)) + ->method('lang') + ->with($question) + ->willReturn(strtoupper($question)); + $this->language->expects($this->at(1)) + ->method('lang') + ->with($answer) + ->willReturn(strtoupper($answer)); + + $this->template->expects($this->once()) + ->method('assign_block_vars') + ->with('faq_block.faq_row', array( + 'FAQ_QUESTION' => strtoupper($question), + 'FAQ_ANSWER' => strtoupper($answer), + )); + + $this->manager->add_question($question, $answer); + } + + public function test_add_block_double_switch() + { + $block_name = 'abc'; + $switch_expected = true; + + $this->language->expects($this->at(0)) + ->method('lang') + ->with($block_name) + ->willReturn(strtoupper($block_name)); + + $this->template->expects($this->at(0)) + ->method('assign_block_vars') + ->with('faq_block', array( + 'BLOCK_TITLE' => strtoupper($block_name), + 'SWITCH_COLUMN' => $switch_expected, + )); + + $this->manager->add_block($block_name, true); + $this->assertTrue($this->manager->switched_column()); + + // Add a second block with switch + $block_name = 'def'; + $switch_expected = false; + + $this->language->expects($this->at(0)) + ->method('lang') + ->with($block_name) + ->willReturn(strtoupper($block_name)); + + $this->template->expects($this->at(0)) + ->method('assign_block_vars') + ->with('faq_block', array( + 'BLOCK_TITLE' => strtoupper($block_name), + 'SWITCH_COLUMN' => $switch_expected, + )); + + $this->manager->add_block($block_name, true); + $this->assertTrue($this->manager->switched_column()); + } +} diff --git a/tests/installer/database_helper_test.php b/tests/installer/database_helper_test.php new file mode 100644 index 0000000000..ed355884f6 --- /dev/null +++ b/tests/installer/database_helper_test.php @@ -0,0 +1,157 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_installer_database_helper_test extends phpbb_test_case +{ + /** + * @var phpbb\install\helper\database + */ + private $database_helper; + + public function setUp() + { + $filesystem = new \phpbb\filesystem\filesystem(); + $phpbb_root_path = ''; + $this->database_helper = new \phpbb\install\helper\database($filesystem, $phpbb_root_path); + } + + /** + * @param string $input + * @param string $expected + * + * @dataProvider comment_string_provider + */ + public function test_remove_comments($input, $expected) + { + $this->assertEquals($expected, $this->database_helper->remove_comments($input)); + } + + /** + * @param array $expected + * @param string $sql + * @param string $delimiter + * + * @dataProvider sql_file_string_provider + */ + public function test_split_sql($expected, $sql, $delimiter) + { + $this->assertEquals($expected, $this->database_helper->split_sql_file($sql, $delimiter)); + } + + /** + * @param bool|array $expected + * @param string $test_string + * + * @dataProvider prefix_test_case_provider + */ + public function test_validate_table_prefix($expected, $test_string) + { + $db_helper_mock = $this->getMockBuilder('\phpbb\install\helper\database') + ->setMethods(array('get_available_dbms')) + ->disableOriginalConstructor() + ->getMock(); + + $db_helper_mock->method('get_available_dbms') + ->willReturn(array('sqlite3' => array( + 'LABEL' => 'SQLite3', + 'SCHEMA' => 'sqlite', + 'MODULE' => 'sqlite3', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\sqlite3', + 'AVAILABLE' => true, + '2.0.x' => false, + ))); + + $this->assertEquals($expected, $db_helper_mock->validate_table_prefix('sqlite3', $test_string)); + } + + // Data provider for the remove comments function + public function comment_string_provider() + { + return array( + array( + 'abc', + 'abc', + ), + array( + 'abc /* asdf */', + "abc \n", + ), + array( + 'abc /* asdf */ f', + "abc \n f", + ), + array( + '# abc', + "\n", + ), + ); + } + + // Data provider for the sql file splitter function + public function sql_file_string_provider() + { + return array( + array( + array( + 'abcd "efgh"' . "\n" . 'qwerty', + 'SELECT * FROM table', + ), + 'abcd "efgh"' . "\n" . + 'qwerty;' . "\n" . + 'SELECT * FROM table', + ';', + ), + ); + } + + // Test data for prefix test + public function prefix_test_case_provider() + { + return array( + array( + true, + 'phpbb_', + ), + array( + true, + 'phpbb', + ), + array( + array( + array('title' => 'INST_ERR_DB_INVALID_PREFIX'), + ), + '1hpbb_', + ), + array( + array( + array('title' => 'INST_ERR_DB_INVALID_PREFIX'), + ), + '?hpbb_', + ), + array( + array( + array('title' => array('INST_ERR_PREFIX_TOO_LONG', 200)), + ), + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + ), + array( + array( + array('title' => 'INST_ERR_DB_INVALID_PREFIX'), + array('title' => array('INST_ERR_PREFIX_TOO_LONG', 200)), + ), + '_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + ), + ); + } +} diff --git a/tests/installer/installer_config_test.php b/tests/installer/installer_config_test.php new file mode 100644 index 0000000000..13ac325a79 --- /dev/null +++ b/tests/installer/installer_config_test.php @@ -0,0 +1,80 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +use phpbb\install\helper\config; + +class phpbb_installer_config_test extends phpbb_test_case +{ + /** + * @var \phpbb\install\helper\config + */ + private $config; + + public function setUp() + { + $phpbb_root_path = __DIR__ . './../../phpBB/'; + $filesystem = $this->getMock('\phpbb\filesystem\filesystem'); + $php_ini = $this->getMockBuilder('\bantu\IniGetWrapper\IniGetWrapper') + ->getMock(); + $php_ini->method('getInt') + ->willReturn(-1); + $php_ini->method('getBytes') + ->willReturn(-1); + + $this->config = new config($filesystem, $php_ini, $phpbb_root_path); + } + + public function test_set_get_var() + { + $this->config->set('foo', 'bar'); + $this->assertEquals('bar', $this->config->get('foo')); + } + + public function test_get_time_remaining() + { + $this->assertGreaterThan(0, $this->config->get_time_remaining()); + } + + public function test_get_memory_remaining() + { + $this->assertGreaterThan(0, $this->config->get_memory_remaining()); + } + + public function test_progress_tracking() + { + $this->config->set_finished_task(0); + $this->config->set_active_module('bar', 5); + $this->config->set_task_progress_count(10); + $this->config->increment_current_task_progress(); + + $progress_data = $this->config->get_progress_data(); + $this->assertEquals(1, $progress_data['current_task_progress']); + + $this->config->increment_current_task_progress(2); + + // We only want to check these values + $result = $this->config->get_progress_data(); + $expected_result = array( + 'last_task_module_name' => 'bar', + 'last_task_module_index' => 5, + 'last_task_index' => 0, + 'max_task_progress' => 10, + 'current_task_progress' => 3, + ); + + foreach ($expected_result as $key => $value) + { + $this->assertEquals($value, $result[$key]); + } + } +} diff --git a/tests/installer/mocks/test_installer_module.php b/tests/installer/mocks/test_installer_module.php new file mode 100644 index 0000000000..e6ebbba263 --- /dev/null +++ b/tests/installer/mocks/test_installer_module.php @@ -0,0 +1,20 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class test_installer_module extends \phpbb\install\module_base +{ + public function get_navigation_stage_path() + { + return array(); + } +} diff --git a/tests/installer/mocks/test_installer_task_mock.php b/tests/installer/mocks/test_installer_task_mock.php new file mode 100644 index 0000000000..ccd62b3bf4 --- /dev/null +++ b/tests/installer/mocks/test_installer_task_mock.php @@ -0,0 +1,44 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class test_installer_task_mock extends \phpbb\install\task_base +{ + private $task_was_runned; + + public function __construct() + { + $this->task_was_runned = false; + + parent::__construct(); + } + + public function run() + { + $this->task_was_runned = true; + } + + public function was_task_runned() + { + return $this->task_was_runned; + } + + public function get_task_lang_name() + { + return ''; + } + + public static function get_step_count() + { + return 2; + } +} diff --git a/tests/installer/module_base_test.php b/tests/installer/module_base_test.php new file mode 100644 index 0000000000..9578010047 --- /dev/null +++ b/tests/installer/module_base_test.php @@ -0,0 +1,65 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +require_once __DIR__ . '/mocks/test_installer_task_mock.php'; +require_once __DIR__ . '/mocks/test_installer_module.php'; + +class module_base_test extends phpbb_test_case +{ + /** + * @var \phpbb\install\module_interface + */ + protected $module; + + /** + * @var phpbb_mock_container_builder + */ + protected $container; + + public function setUp() + { + // DI container mock + $this->container = new phpbb_mock_container_builder(); + $this->container->set('task_one', new test_installer_task_mock()); + $this->container->set('task_two', new test_installer_task_mock()); + + // the collection + $module_collection = new \phpbb\di\ordered_service_collection($this->container); + $module_collection->add('task_one'); + $module_collection->add('task_two'); + $module_collection->add_service_class('task_one', 'test_installer_task_mock'); + $module_collection->add_service_class('task_two', 'test_installer_task_mock'); + + $this->module = new test_installer_module($module_collection, true, false); + + $iohandler = $this->getMock('\phpbb\install\helper\iohandler\iohandler_interface'); + $config = new \phpbb\install\helper\config(new \phpbb\filesystem\filesystem(), new \bantu\IniGetWrapper\IniGetWrapper(), '', 'php'); + $this->module->setup($config, $iohandler); + } + + public function test_run() + { + $this->module->run(); + + $task = $this->container->get('task_one'); + $this->assertTrue($task->was_task_runned()); + + $task = $this->container->get('task_two'); + $this->assertTrue($task->was_task_runned()); + } + + public function test_step_count() + { + $this->assertEquals(4, $this->module->get_step_count()); + } +} diff --git a/tests/installer/navigation_provider_test.php b/tests/installer/navigation_provider_test.php new file mode 100644 index 0000000000..ea39af66cd --- /dev/null +++ b/tests/installer/navigation_provider_test.php @@ -0,0 +1,34 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_installer_navigation_provider_test extends phpbb_test_case +{ + public function test_navigation() + { + // Mock nav interface + $nav_stub = $this->getMockBuilder('\phpbb\install\helper\navigation\navigation_interface') + ->getMock(); + $nav_stub->method('get') + ->willReturn(array('foo' => 'bar')); + + // Set up dependencies + $container = new phpbb_mock_container_builder(); + $container->set('foo', $nav_stub); + $nav_collection = new \phpbb\di\service_collection($container); + $nav_collection->add('foo'); + + // Let's test + $nav_provider = new \phpbb\install\helper\navigation\navigation_provider($nav_collection); + $this->assertEquals(array('foo' => 'bar'), $nav_provider->get()); + } +} diff --git a/tests/language/language_test.php b/tests/language/language_test.php new file mode 100644 index 0000000000..29b4873dcb --- /dev/null +++ b/tests/language/language_test.php @@ -0,0 +1,243 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_language_test extends phpbb_test_case +{ + /** @var \phpbb\language\language */ + protected $lang; + + public function setUp() + { + global $phpbb_root_path, $phpEx; + + // Set up language service + $this->lang = new \phpbb\language\language( + new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx) + ); + + // Set up language data for testing + $reflection_class = new ReflectionClass('\phpbb\language\language'); + + // Set default language files loaded flag to true + $loaded_flag = $reflection_class->getProperty('common_language_files_loaded'); + $loaded_flag->setAccessible(true); + $loaded_flag->setValue($this->lang, true); + + // Set up test language data + $lang_array = $reflection_class->getProperty('lang'); + $lang_array->setAccessible(true); + $lang_array->setValue($this->lang, $this->get_test_data_set()); + } + + public function test_is_set() + { + // Check for non-existing key + $this->assertFalse($this->lang->is_set('VALUE')); + $this->assertFalse($this->lang->is_set(array('dateformat', 'MAYBE'))); + + // Check for existing key + $this->assertTrue($this->lang->is_set('FOO')); + $this->assertTrue($this->lang->is_set(array('dateformat', 'AGO'))); + + // Array doesn't exist at all... + $this->assertFalse($this->lang->is_set(array('PHPBB', 'PHP'))); + } + + public function test_lang_raw() + { + $this->assertEquals($this->lang->lang_raw('FOO'), 'BAR'); + $this->assertEquals($this->lang->lang_raw('VOID'), 'VOID'); + $this->assertEquals($this->lang->lang_raw('ARRY'), array( + 0 => 'No posts', // 0 + 1 => '1 post', // 1 + 2 => '%d posts', // 2+ + )); + } + + public function test_lang_array() + { + $this->assertEquals($this->lang->lang_array('FOO'), 'BAR'); + $this->assertEquals($this->lang->lang_array('VOID'), 'VOID'); + $this->assertEquals($this->lang->lang_array('ARRY', [0]), 'No posts'); + $this->assertEquals($this->lang->lang_array('FOO', [2, 3, 'BARZ']), 'BAR'); + } + + public function test_lang() + { + // No param + $this->assertEquals($this->lang->lang('FOO'), 'BAR'); + $this->assertEquals($this->lang->lang('EMPTY'), ''); + $this->assertEquals($this->lang->lang('ZERO'), '0'); + + // Invalid index + $this->assertEquals($this->lang->lang('VOID'), 'VOID'); + + // Unnecessary param + $this->assertEquals($this->lang->lang('FOO', 2), 'BAR'); + $this->assertEquals($this->lang->lang('FOO', 2, 3), 'BAR'); + $this->assertEquals($this->lang->lang('FOO', 2, 3, 'BARZ'), 'BAR'); + + // String + $this->assertEquals($this->lang->lang('STR', 24, 'x', 42), '24 x, 42 topics'); + $this->assertEquals($this->lang->lang('STR2', 64), '64 foos'); + + // Array + $this->assertEquals($this->lang->lang('ARRY', 0), 'No posts'); + $this->assertEquals($this->lang->lang('ARRY', 1), '1 post'); + $this->assertEquals($this->lang->lang('ARRY', 2), '2 posts'); + $this->assertEquals($this->lang->lang('ARRY', 123), '123 posts'); + + // Empty array returns the language key + $this->assertEquals($this->lang->lang('ARRY_EMPTY', 123), 'ARRY_EMPTY'); + + // No 0 key defined + $this->assertEquals($this->lang->lang('ARRY_NO_ZERO', 0), '0 posts'); + $this->assertEquals($this->lang->lang('ARRY_NO_ZERO', 1), '1 post'); + $this->assertEquals($this->lang->lang('ARRY_NO_ZERO', 2), '2 posts'); + + // Array with missing keys + $this->assertEquals($this->lang->lang('ARRY_MISSING', 2), '2 post'); + + // Floats as array key + $this->assertEquals($this->lang->lang('ARRY_FLOAT', 1.3), '1 post'); + $this->assertEquals($this->lang->lang('ARRY_FLOAT', 2.0), '2.0 posts'); + $this->assertEquals($this->lang->lang('ARRY_FLOAT', 2.51), '2.5 posts'); + + // Use sub key, if first paramenter is an array + $this->assertEquals($this->lang->lang(array('dateformat', 'AGO'), 2), '2 seconds'); + + // ticket PHPBB3-9949 - use first int to determinate the plural-form to use + $this->assertEquals($this->lang->lang('ARRY', 1, 2), '1 post'); + $this->assertEquals($this->lang->lang('ARRY', 1, 's', 2), '1 post'); + } + + public function test_lang_plural_rules() + { + $this->assertEquals($this->lang->lang('PLURAL_ARRY', 0), '0 is 0'); + $this->assertEquals($this->lang->lang('PLURAL_ARRY', 1), '1 is 1'); + $this->assertEquals($this->lang->lang('PLURAL_ARRY', 103), '103 ends with 01-10'); + $this->assertEquals($this->lang->lang('PLURAL_ARRY', 15), '15 ends with 11-19'); + $this->assertEquals($this->lang->lang('PLURAL_ARRY', 300), '300 is part of the last rule'); + } + + public function test_lang_bc() + { + $user = new \phpbb\user($this->lang, '\phpbb\datetime'); + + // Test lang array access + $this->assertEquals($user->lang['FOO'], 'BAR'); + + // No param + $this->assertEquals($user->lang('FOO'), 'BAR'); + $this->assertEquals($user->lang('EMPTY'), ''); + $this->assertEquals($user->lang('ZERO'), '0'); + + // Invalid index + $this->assertEquals($user->lang('VOID'), 'VOID'); + + // Unnecessary param + $this->assertEquals($user->lang('FOO', 2), 'BAR'); + $this->assertEquals($user->lang('FOO', 2, 3), 'BAR'); + $this->assertEquals($user->lang('FOO', 2, 3, 'BARZ'), 'BAR'); + + // String + $this->assertEquals($user->lang('STR', 24, 'x', 42), '24 x, 42 topics'); + $this->assertEquals($user->lang('STR2', 64), '64 foos'); + + // Array + $this->assertEquals($user->lang('ARRY', 0), 'No posts'); + $this->assertEquals($user->lang('ARRY', 1), '1 post'); + $this->assertEquals($user->lang('ARRY', 2), '2 posts'); + $this->assertEquals($user->lang('ARRY', 123), '123 posts'); + + // Empty array returns the language key + $this->assertEquals($user->lang('ARRY_EMPTY', 123), 'ARRY_EMPTY'); + + // No 0 key defined + $this->assertEquals($user->lang('ARRY_NO_ZERO', 0), '0 posts'); + $this->assertEquals($user->lang('ARRY_NO_ZERO', 1), '1 post'); + $this->assertEquals($user->lang('ARRY_NO_ZERO', 2), '2 posts'); + + // Array with missing keys + $this->assertEquals($user->lang('ARRY_MISSING', 2), '2 post'); + + // Floats as array key + $this->assertEquals($user->lang('ARRY_FLOAT', 1.3), '1 post'); + $this->assertEquals($user->lang('ARRY_FLOAT', 2.0), '2.0 posts'); + $this->assertEquals($user->lang('ARRY_FLOAT', 2.51), '2.5 posts'); + + // Use sub key, if first paramenter is an array + $this->assertEquals($user->lang(array('dateformat', 'AGO'), 2), '2 seconds'); + + // ticket PHPBB3-9949 - use first int to determinate the plural-form to use + $this->assertEquals($user->lang('ARRY', 1, 2), '1 post'); + $this->assertEquals($user->lang('ARRY', 1, 's', 2), '1 post'); + } + + public function test_lang_plural_rules_bc() + { + $user = new \phpbb\user($this->lang, '\phpbb\datetime'); + + // ticket PHPBB3-10345 - different plural rules, not just 0/1/2+ + $this->assertEquals($user->lang('PLURAL_ARRY', 0), '0 is 0'); + $this->assertEquals($user->lang('PLURAL_ARRY', 1), '1 is 1'); + $this->assertEquals($user->lang('PLURAL_ARRY', 103), '103 ends with 01-10'); + $this->assertEquals($user->lang('PLURAL_ARRY', 15), '15 ends with 11-19'); + $this->assertEquals($user->lang('PLURAL_ARRY', 300), '300 is part of the last rule'); + } + + protected function get_test_data_set() + { + return array( + 'FOO' => 'BAR', + 'BARZ' => 'PENG', + 'EMPTY' => '', + 'ZERO' => '0', + 'STR' => '%d %s, %d topics', + 'STR2' => '%d foos', + 'ARRY' => array( + 0 => 'No posts', // 0 + 1 => '1 post', // 1 + 2 => '%d posts', // 2+ + ), + 'ARRY_NO_ZERO' => array( + 1 => '1 post', // 1 + 2 => '%d posts', // 0, 2+ + ), + 'ARRY_MISSING' => array( + 1 => '%d post', // 1 + //Missing second plural + ), + 'ARRY_FLOAT' => array( + 1 => '1 post', // 1.x + 2 => '%1$.1f posts', // 0.x, 2+.x + ), + 'ARRY_EMPTY' => array( + ), + 'dateformat' => array( + 'AGO' => array( + 1 => '%d second', + 2 => '%d seconds', + ), + ), + 'PLURAL_RULE' => 13, + 'PLURAL_ARRY' => array( + 0 => '%d is 0', // 0 + 1 => '%d is 1', // 1 + 2 => '%d ends with 01-10', // ending with 01-10 + 3 => '%d ends with 11-19', // ending with 11-19 + 4 => '%d is part of the last rule', // everything else + ), + ); + } +} diff --git a/tests/lock/db_test.php b/tests/lock/db_test.php index 6fc813cb38..389eab4152 100644 --- a/tests/lock/db_test.php +++ b/tests/lock/db_test.php @@ -30,7 +30,6 @@ class phpbb_lock_db_test extends phpbb_database_test_case $db = $this->db = $this->new_dbal(); $config = $this->config = new \phpbb\config\config(array('rand_seed' => '', 'rand_seed_last_update' => '0')); - set_config(null, null, null, $this->config); $this->lock = new \phpbb\lock\db('test_lock', $this->config, $this->db); } diff --git a/tests/log/add_test.php b/tests/log/add_test.php index 29d3adaeb6..ea1ae74d53 100644 --- a/tests/log/add_test.php +++ b/tests/log/add_test.php @@ -27,7 +27,9 @@ class phpbb_log_add_test extends phpbb_database_test_case $db = $this->new_dbal(); $cache = new phpbb_mock_cache; $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $auth = $this->getMock('\phpbb\auth\auth'); $log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE); @@ -56,7 +58,9 @@ class phpbb_log_add_test extends phpbb_database_test_case $db = $this->new_dbal(); $cache = new phpbb_mock_cache; $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $auth = $this->getMock('\phpbb\auth\auth'); $log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE); diff --git a/tests/log/delete_test.php b/tests/log/delete_test.php index ec43182a0c..fe4c3835cb 100644 --- a/tests/log/delete_test.php +++ b/tests/log/delete_test.php @@ -30,7 +30,9 @@ class phpbb_log_delete_test extends phpbb_database_test_case $db = $this->new_dbal(); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->data['user_id'] = 1; $auth = $this->getMock('\phpbb\auth\auth'); diff --git a/tests/log/fixtures/delete_log.xml b/tests/log/fixtures/delete_log.xml index 4b2402102e..393c686f0c 100644 --- a/tests/log/fixtures/delete_log.xml +++ b/tests/log/fixtures/delete_log.xml @@ -6,6 +6,7 @@ <column>user_id</column> <column>forum_id</column> <column>topic_id</column> + <column>post_id</column> <column>reportee_id</column> <column>log_ip</column> <column>log_time</column> @@ -18,6 +19,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_INSTALL_INSTALLED</value> @@ -30,6 +32,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_KEY_NOT_EXISTS</value> @@ -42,6 +45,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_CRITICAL</value> @@ -54,6 +58,7 @@ <value>12</value> <value>34</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD</value> @@ -66,6 +71,7 @@ <value>12</value> <value>45</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD</value> @@ -78,6 +84,7 @@ <value>23</value> <value>56</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD</value> @@ -90,6 +97,7 @@ <value>12</value> <value>45</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD2</value> @@ -101,6 +109,7 @@ <value>1</value> <value>0</value> <value>0</value> + <value>0</value> <value>2</value> <value>127.0.0.1</value> <value>1</value> @@ -113,6 +122,7 @@ <value>1</value> <value>0</value> <value>0</value> + <value>0</value> <value>1</value> <value>127.0.0.1</value> <value>1</value> @@ -126,6 +136,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_SINGULAR_PLURAL</value> @@ -138,6 +149,7 @@ <value>15</value> <value>3</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD3</value> @@ -150,6 +162,7 @@ <value>13</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value></value> @@ -162,6 +175,7 @@ <value>14</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value></value> @@ -174,6 +188,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value></value> @@ -186,6 +201,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value></value> diff --git a/tests/log/fixtures/empty_log.xml b/tests/log/fixtures/empty_log.xml index 261b6a622a..47fd639b17 100644 --- a/tests/log/fixtures/empty_log.xml +++ b/tests/log/fixtures/empty_log.xml @@ -6,6 +6,7 @@ <column>user_id</column> <column>forum_id</column> <column>topic_id</column> + <column>post_id</column> <column>reportee_id</column> <column>log_ip</column> <column>log_time</column> diff --git a/tests/log/fixtures/full_log.xml b/tests/log/fixtures/full_log.xml index ef35884444..5b9ded9ffb 100644 --- a/tests/log/fixtures/full_log.xml +++ b/tests/log/fixtures/full_log.xml @@ -6,6 +6,7 @@ <column>user_id</column> <column>forum_id</column> <column>topic_id</column> + <column>post_id</column> <column>reportee_id</column> <column>log_ip</column> <column>log_time</column> @@ -18,6 +19,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_INSTALL_INSTALLED</value> @@ -30,6 +32,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_KEY_NOT_EXISTS</value> @@ -42,6 +45,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_CRITICAL</value> @@ -54,6 +58,7 @@ <value>12</value> <value>34</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD</value> @@ -66,6 +71,7 @@ <value>12</value> <value>45</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD</value> @@ -78,6 +84,7 @@ <value>23</value> <value>56</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD</value> @@ -90,6 +97,7 @@ <value>12</value> <value>45</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD2</value> @@ -101,6 +109,7 @@ <value>1</value> <value>0</value> <value>0</value> + <value>0</value> <value>2</value> <value>127.0.0.1</value> <value>1</value> @@ -113,6 +122,7 @@ <value>1</value> <value>0</value> <value>0</value> + <value>0</value> <value>1</value> <value>127.0.0.1</value> <value>1</value> @@ -126,6 +136,7 @@ <value>0</value> <value>0</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_SINGULAR_PLURAL</value> @@ -138,6 +149,7 @@ <value>15</value> <value>3</value> <value>0</value> + <value>0</value> <value>127.0.0.1</value> <value>1</value> <value>LOG_MOD3</value> diff --git a/tests/log/function_add_log_test.php b/tests/log/function_add_log_test.php index 63e468498e..cdfeb52996 100644 --- a/tests/log/function_add_log_test.php +++ b/tests/log/function_add_log_test.php @@ -11,7 +11,7 @@ * */ -require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_compatibility.php'; class phpbb_log_function_add_log_test extends phpbb_database_test_case { @@ -161,7 +161,10 @@ class phpbb_log_function_add_log_test extends phpbb_database_test_case $db = $this->new_dbal(); $cache = new phpbb_mock_cache; $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $auth = $this->getMock('\phpbb\auth\auth'); $phpbb_log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE); diff --git a/tests/log/function_view_log_test.php b/tests/log/function_view_log_test.php index 02e0b3912f..81b1f4a78c 100644 --- a/tests/log/function_view_log_test.php +++ b/tests/log/function_view_log_test.php @@ -46,6 +46,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 0, 'topic_id' => 0, + 'post_id' => 0, 'viewforum' => '', 'action' => 'LOG_INSTALL_INSTALLED 3.1.0-dev', @@ -65,6 +66,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 0, 'topic_id' => 0, + 'post_id' => 0, 'viewforum' => '', 'action' => '{LOG KEY NOT EXISTS}<br />additional_data', @@ -84,6 +86,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 0, 'topic_id' => 0, + 'post_id' => 0, 'viewforum' => '', 'action' => '{LOG CRITICAL}<br />critical data', @@ -103,10 +106,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 12, 'topic_id' => 34, + 'post_id' => 0, 'viewforum' => '', 'action' => '{LOG MOD}', 'viewtopic' => '', + 'viewpost' => '', 'viewlogs' => '', ), 5 => array( @@ -124,10 +129,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 12, 'topic_id' => 45, + 'post_id' => 0, 'viewforum' => '', 'action' => '{LOG MOD}', 'viewtopic' => '', + 'viewpost' => '', 'viewlogs' => '', ), 6 => array( @@ -145,10 +152,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 23, 'topic_id' => 56, + 'post_id' => 0, 'viewforum' => append_sid("phpBB/viewforum.$phpEx", 'f=23'), 'action' => '{LOG MOD}', 'viewtopic' => append_sid("phpBB/viewtopic.$phpEx", 'f=23&t=56'), + 'viewpost' => '', 'viewlogs' => append_sid("phpBB/mcp.$phpEx", 'i=logs&mode=topic_logs&t=56'), ), 7 => array( @@ -166,10 +175,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 12, 'topic_id' => 45, + 'post_id' => 0, 'viewforum' => '', 'action' => 'LOG_MOD2', 'viewtopic' => '', + 'viewpost' => '', 'viewlogs' => '', ), 8 => array( @@ -187,6 +198,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 0, 'topic_id' => 0, + 'post_id' => 0, 'viewforum' => '', 'action' => 'LOG_USER admin', @@ -206,6 +218,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 0, 'topic_id' => 0, + 'post_id' => 0, 'viewforum' => '', 'action' => 'LOG_USER guest', @@ -225,6 +238,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 0, 'topic_id' => 0, + 'post_id' => 0, 'viewforum' => '', 'action' => 'LOG_SINGULAR_PLURAL 2', @@ -244,10 +258,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case 'time' => 1, 'forum_id' => 15, 'topic_id' => 3, + 'post_id' => 0, 'viewforum' => '', 'action' => 'LOG_MOD3 guest ', 'viewtopic' => '', + 'viewpost' => '', 'viewlogs' => '', ), ); diff --git a/tests/migrator/convert_timezones_test.php b/tests/migrator/convert_timezones_test.php index 7501ed2ed0..f8d780da0c 100644 --- a/tests/migrator/convert_timezones_test.php +++ b/tests/migrator/convert_timezones_test.php @@ -18,7 +18,8 @@ class phpbb_migrator_convert_timezones_test extends phpbb_database_test_case public function getDataSet() { $this->db = $this->new_dbal(); - $db_tools = new \phpbb\db\tools($this->db); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($this->db); // user_dst doesn't exist anymore, must re-add it to test this $db_tools->sql_column_add('phpbb_users', 'user_dst', array('BOOL', 1)); @@ -55,11 +56,12 @@ class phpbb_migrator_convert_timezones_test extends phpbb_database_test_case global $phpbb_root_path, $phpEx; $this->db = $this->new_dbal(); + $factory = new \phpbb\db\tools\factory(); $this->migration = new \phpbb\db\migration\data\v310\timezone( new \phpbb\config\config(array()), $this->db, - new \phpbb\db\tools($this->db), + $factory->get($this->db), $phpbb_root_path, $phpEx, 'phpbb_' @@ -90,7 +92,8 @@ class phpbb_migrator_convert_timezones_test extends phpbb_database_test_case } $this->db->sql_freeresult($result); - $db_tools = new \phpbb\db\tools($this->db); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($this->db); // Remove the user_dst field again $db_tools->sql_column_remove('phpbb_users', 'user_dst'); diff --git a/tests/migrator/schema_generator_test.php b/tests/migrator/schema_generator_test.php index 9adf518a5d..40a8343e22 100644 --- a/tests/migrator/schema_generator_test.php +++ b/tests/migrator/schema_generator_test.php @@ -30,7 +30,8 @@ class schema_generator_test extends phpbb_test_case $this->config = new \phpbb\config\config(array()); $this->db = new \phpbb\db\driver\sqlite(); - $this->db_tools = new \phpbb\db\tools($this->db); + $factory = new \phpbb\db\tools\factory(); + $this->db_tools = $factory->get($this->db); $this->table_prefix = 'phpbb_'; } diff --git a/tests/mock/container_builder.php b/tests/mock/container_builder.php index 297e3a65e6..134589b0b8 100644 --- a/tests/mock/container_builder.php +++ b/tests/mock/container_builder.php @@ -52,7 +52,15 @@ class phpbb_mock_container_builder implements ContainerInterface { if ($this->has($id)) { - return $this->services[$id]; + $service = $this->services[$id]; + if (is_array($service) && is_callable($service[0])) + { + return call_user_func_array($service[0], $service[1]); + } + else + { + return $service; + } } throw new Exception('Could not find service: ' . $id); @@ -180,4 +188,9 @@ class phpbb_mock_container_builder implements ContainerInterface public function isScopeActive($name) { } + + public function isFrozen() + { + return false; + } } diff --git a/tests/mock/controller_helper.php b/tests/mock/controller_helper.php index ae3e7bf432..0116dced49 100644 --- a/tests/mock/controller_helper.php +++ b/tests/mock/controller_helper.php @@ -13,20 +13,6 @@ class phpbb_mock_controller_helper extends \phpbb\controller\helper { - public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext, $phpbb_root_path_ext) - { - $this->template = $template; - $this->user = $user; - $this->config = $config; - $this->symfony_request = $symfony_request; - $this->request = $request; - $this->filesystem = $filesystem; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - $provider->find_routing_files($manager->get_finder()); - $this->route_collection = $provider->find($phpbb_root_path_ext)->get_routes(); - } - public function get_current_url() { return ''; diff --git a/tests/mock/extension_manager.php b/tests/mock/extension_manager.php index 3b759fbbc2..2ce61c5149 100644 --- a/tests/mock/extension_manager.php +++ b/tests/mock/extension_manager.php @@ -18,7 +18,7 @@ class phpbb_mock_extension_manager extends \phpbb\extension\manager $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = 'php'; $this->extensions = $extensions; - $this->filesystem = new \phpbb\filesystem(); + $this->filesystem = new \phpbb\filesystem\filesystem(); $this->container = $container; } } diff --git a/tests/mock/fileupload.php b/tests/mock/fileupload.php index 8cc4d77ea1..5a0afc6cd3 100644 --- a/tests/mock/fileupload.php +++ b/tests/mock/fileupload.php @@ -19,9 +19,10 @@ class phpbb_mock_fileupload { public $max_filesize = 100; public $error_prefix = ''; + public $valid_dimensions = true; public function valid_dimensions($filespec) { - return true; + return $this->valid_dimensions; } } diff --git a/tests/mock/migrator.php b/tests/mock/migrator.php index 293f115335..4d1aca0a0a 100644 --- a/tests/mock/migrator.php +++ b/tests/mock/migrator.php @@ -21,10 +21,6 @@ class phpbb_mock_migrator extends \phpbb\db\migrator { } - public function set_migrations($class_names) - { - } - public function update() { } diff --git a/tests/mock/notification_manager.php b/tests/mock/notification_manager.php index 6a590bc0ca..952c0db489 100644 --- a/tests/mock/notification_manager.php +++ b/tests/mock/notification_manager.php @@ -32,19 +32,18 @@ class phpbb_mock_notification_manager ); } - public function mark_notifications_read() + public function mark_notifications() { } - public function mark_notifications_read_by_parent() + public function mark_notifications_by_parent() { } - public function mark_notifications_read_by_id() + public function mark_notifications_by_id() { } - public function add_notifications() { return array(); diff --git a/tests/mock/notification_type_post.php b/tests/mock/notification_type_post.php index 6d8f6dc504..4116fecf5e 100644 --- a/tests/mock/notification_type_post.php +++ b/tests/mock/notification_type_post.php @@ -21,11 +21,12 @@ if (!defined('IN_PHPBB')) class phpbb_mock_notification_type_post extends \phpbb\notification\type\post { - public function __construct($user_loader, $db, $cache, $user, $auth, $config, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table) + public function __construct($user_loader, $db, $cache, $language, $user, $auth, $config, $phpbb_root_path, $php_ext, $notification_types_table, $user_notifications_table) { $this->user_loader = $user_loader; $this->db = $db; $this->cache = $cache; + $this->language = $language; $this->user = $user; $this->auth = $auth; $this->config = $config; @@ -34,7 +35,6 @@ class phpbb_mock_notification_type_post extends \phpbb\notification\type\post $this->php_ext = $php_ext; $this->notification_types_table = $notification_types_table; - $this->notifications_table = $notifications_table; - $this->user_notifications_table = $user_notifications_table; + $this->user_notifications_table = $user_notifications_table; } } diff --git a/tests/mock/phpbb_di_container_builder.php b/tests/mock/phpbb_di_container_builder.php index 59cdf0bb2b..23dc3d1e8b 100644 --- a/tests/mock/phpbb_di_container_builder.php +++ b/tests/mock/phpbb_di_container_builder.php @@ -17,4 +17,14 @@ class phpbb_mock_phpbb_di_container_builder extends \phpbb\di\container_builder { return $this->phpbb_root_path . '../../tmp/container.' . $this->php_ext; } + + /** + * Get the filename under which the dumped extensions autoloader will be stored. + * + * @return string Path for dumped extensions autoloader + */ + protected function get_autoload_filename() + { + return $this->phpbb_root_path . '../../tmp/autoload.' . $this->php_ext; + } } diff --git a/tests/mock/router.php b/tests/mock/router.php new file mode 100644 index 0000000000..01faa338c5 --- /dev/null +++ b/tests/mock/router.php @@ -0,0 +1,27 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +class phpbb_mock_router extends \phpbb\routing\router +{ + public function get_matcher() + { + $this->create_new_url_matcher(); + return parent::get_matcher(); + } + + public function get_generator() + { + $this->create_new_url_generator(); + return parent::get_generator(); + } +} diff --git a/tests/notification/base.php b/tests/notification/base.php index 162feae557..b64e25cf8c 100644 --- a/tests/notification/base.php +++ b/tests/notification/base.php @@ -11,6 +11,10 @@ * */ +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; + require_once dirname(__FILE__) . '/manager_helper.php'; abstract class phpbb_tests_notification_base extends phpbb_database_test_case @@ -39,6 +43,13 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case ); } + protected function get_notification_methods() + { + return array( + 'notification.method.board', + ); + } + protected function setUp() { parent::setUp(); @@ -55,55 +66,83 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case 'allow_bookmarks' => true, 'allow_topic_notify' => true, 'allow_forum_notify' => true, + 'allow_board_notifications' => true, )); - $user = $this->user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $this->user = $user; $this->user_loader = new \phpbb\user_loader($this->db, $phpbb_root_path, $phpEx, 'phpbb_users'); $auth = $this->auth = new phpbb_mock_notifications_auth(); + $cache_driver = new \phpbb\cache\driver\dummy(); $cache = $this->cache = new \phpbb\cache\service( - new \phpbb\cache\driver\null(), + $cache_driver, $this->config, $this->db, $phpbb_root_path, $phpEx ); - + $this->phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $phpbb_container = $this->container = new phpbb_mock_container_builder(); + $phpbb_container = $this->container = new ContainerBuilder(); + $loader = new YamlFileLoader($phpbb_container, new FileLocator(__DIR__ . '/fixtures')); + $loader->load('services_notification.yml'); + $phpbb_container->set('user_loader', $this->user_loader); + $phpbb_container->set('user', $user); + $phpbb_container->set('language', $lang); + $phpbb_container->set('config', $this->config); + $phpbb_container->set('dbal.conn', $this->db); + $phpbb_container->set('auth', $auth); + $phpbb_container->set('cache.driver', $cache_driver); + $phpbb_container->set('cache', $cache); + $phpbb_container->set('text_formatter.utils', new \phpbb\textformatter\s9e\utils()); + $phpbb_container->set('dispatcher', $this->phpbb_dispatcher); + $phpbb_container->setParameter('core.root_path', $phpbb_root_path); + $phpbb_container->setParameter('core.php_ext', $phpEx); + $phpbb_container->setParameter('tables.notifications', 'phpbb_notifications'); + $phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications'); + $phpbb_container->setParameter('tables.notification_types', 'phpbb_notification_types'); $this->notifications = new phpbb_notification_manager_helper( array(), array(), $this->container, $this->user_loader, - $this->config, $this->phpbb_dispatcher, $this->db, $this->cache, + $lang, $this->user, - $phpbb_root_path, - $phpEx, 'phpbb_notification_types', - 'phpbb_notifications', 'phpbb_user_notifications' ); $phpbb_container->set('notification_manager', $this->notifications); + $phpbb_container->compile(); $this->notifications->setDependencies($this->auth, $this->config); $types = array(); foreach ($this->get_notification_types() as $type) { - $type_parts = explode('.', $type); - $class = $this->build_type('phpbb\notification\type\\' . array_pop($type_parts)); + $class = $this->build_type($type); $types[$type] = $class; - $this->container->set($type, $class); } $this->notifications->set_var('notification_types', $types); + $methods = array(); + foreach ($this->get_notification_methods() as $method) + { + $class = $this->container->get($method); + + $methods[$method] = $class; + } + + $this->notifications->set_var('notification_methods', $methods); + $this->db->sql_query('DELETE FROM phpbb_notification_types'); $this->db->sql_query('DELETE FROM phpbb_notifications'); $this->db->sql_query('DELETE FROM phpbb_user_notifications'); @@ -111,14 +150,14 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case protected function build_type($type) { - global $phpbb_root_path, $phpEx; + $instance = $this->container->get($type); - return new $type($this->user_loader, $this->db, $this->cache->get_driver(), $this->user, $this->auth, $this->config, $phpbb_root_path, $phpEx, 'phpbb_notification_types', 'phpbb_notifications', 'phpbb_user_notifications'); + return $instance; } protected function assert_notifications($expected, $options = array()) { - $notifications = $this->notifications->load_notifications(array_merge(array( + $notifications = $this->notifications->load_notifications('notification.method.board', array_merge(array( 'count_unread' => true, 'order_by' => 'notification_time', 'order_dir' => 'ASC', diff --git a/tests/notification/convert_test.php b/tests/notification/convert_test.php index 32ab34c9bc..4a7fd89409 100644 --- a/tests/notification/convert_test.php +++ b/tests/notification/convert_test.php @@ -28,11 +28,12 @@ class phpbb_notification_convert_test extends phpbb_database_test_case global $phpbb_root_path, $phpEx; $this->db = $this->new_dbal(); + $factory = new \phpbb\db\tools\factory(); $this->migration = new \phpbb\db\migration\data\v310\notification_options_reconvert( new \phpbb\config\config(array()), $this->db, - new \phpbb\db\tools($this->db), + $factory->get($this->db), $phpbb_root_path, $phpEx, 'phpbb_' diff --git a/tests/notification/ext/test/notification/type/test.php b/tests/notification/ext/test/notification/type/test.php index b02a563f06..7f3b4a4ef1 100644 --- a/tests/notification/ext/test/notification/type/test.php +++ b/tests/notification/ext/test/notification/type/test.php @@ -47,12 +47,13 @@ class test extends \phpbb\notification\type\base { $this->notification_time = $post['post_time']; - return parent::create_insert_array($post, $pre_create_data); + parent::create_insert_array($post, $pre_create_data); } public function create_update_array($type_data) { - $data = $this->create_insert_array($type_data); + $this->create_insert_array($type_data); + $data = $this->get_insert_array(); // Unset data unique to each row unset( diff --git a/tests/notification/fixtures/services_notification.yml b/tests/notification/fixtures/services_notification.yml new file mode 100644 index 0000000000..6e68cccff6 --- /dev/null +++ b/tests/notification/fixtures/services_notification.yml @@ -0,0 +1,76 @@ +imports: + - { resource: ../../../phpBB/config/default/container/services_notification.yml } + +services: + notification_manager: + synthetic: true + + user_loader: + synthetic: true + + user: + synthetic: true + + config: + synthetic: true + + dbal.conn: + synthetic: true + + language: + synthetic: true + + auth: + synthetic: true + + cache.driver: + synthetic: true + + group_helper: + synthetic: true + + path_helper: + synthetic: true + + groupposition.legend: + synthetic: true + + groupposition.teampage: + synthetic: true + + groupposition.teampage: + synthetic: true + + text_formatter.s9e.factory: + synthetic: true + + text_formatter.s9e.quote_helper: + synthetic: true + + text_formatter.parser: + synthetic: true + + text_formatter.s9e.parser: + synthetic: true + + text_formatter.renderer: + synthetic: true + + text_formatter.s9e.renderer: + synthetic: true + + text_formatter.utils: + synthetic: true + + text_formatter.s9e.utils: + synthetic: true + + text_formatter.data_access: + synthetic: true + + test: + class: phpbb\notification\type\test + scope: prototype + parent: notification.type.base + tags: + - { name: notification.type } diff --git a/tests/notification/fixtures/submit_post_notification.type.bookmark.xml b/tests/notification/fixtures/submit_post_notification.type.bookmark.xml index a1413e2cf8..7f069abc59 100644 --- a/tests/notification/fixtures/submit_post_notification.type.bookmark.xml +++ b/tests/notification/fixtures/submit_post_notification.type.bookmark.xml @@ -126,35 +126,35 @@ <value>notification.type.bookmark</value> <value>0</value> <value>2</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.bookmark</value> <value>0</value> <value>3</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.bookmark</value> <value>0</value> <value>4</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.bookmark</value> <value>0</value> <value>5</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.bookmark</value> <value>0</value> <value>6</value> - <value></value> + <value>notification.method.board</value> <value>0</value> </row> </table> diff --git a/tests/notification/fixtures/submit_post_notification.type.post.xml b/tests/notification/fixtures/submit_post_notification.type.post.xml index ed75787c70..a4bf9d3ee4 100644 --- a/tests/notification/fixtures/submit_post_notification.type.post.xml +++ b/tests/notification/fixtures/submit_post_notification.type.post.xml @@ -156,49 +156,49 @@ <value>notification.type.post</value> <value>0</value> <value>2</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.post</value> <value>0</value> <value>3</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.post</value> <value>0</value> <value>4</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.post</value> <value>0</value> <value>5</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.post</value> <value>0</value> <value>6</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.post</value> <value>0</value> <value>7</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.post</value> <value>0</value> <value>8</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> </table> diff --git a/tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml b/tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml index 2dea8e34dd..0a955c48d2 100644 --- a/tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml +++ b/tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml @@ -110,49 +110,49 @@ <value>notification.type.needs_approval</value> <value>0</value> <value>2</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.needs_approval</value> <value>0</value> <value>3</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.needs_approval</value> <value>0</value> <value>4</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.needs_approval</value> <value>0</value> <value>5</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.needs_approval</value> <value>0</value> <value>6</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.needs_approval</value> <value>0</value> <value>7</value> - <value></value> + <value>notification.method.board</value> <value>0</value> </row> <row> <value>notification.type.needs_approval</value> <value>0</value> <value>9</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> </table> diff --git a/tests/notification/fixtures/submit_post_notification.type.quote.xml b/tests/notification/fixtures/submit_post_notification.type.quote.xml index dd5bc620cd..c66830fbf5 100644 --- a/tests/notification/fixtures/submit_post_notification.type.quote.xml +++ b/tests/notification/fixtures/submit_post_notification.type.quote.xml @@ -98,35 +98,35 @@ <value>notification.type.quote</value> <value>0</value> <value>2</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.quote</value> <value>0</value> <value>3</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.quote</value> <value>0</value> <value>4</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.quote</value> <value>0</value> <value>5</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.quote</value> <value>0</value> <value>6</value> - <value></value> + <value>notification.method.board</value> <value>0</value> </row> </table> diff --git a/tests/notification/fixtures/submit_post_notification.type.topic.xml b/tests/notification/fixtures/submit_post_notification.type.topic.xml index 1ba8d05699..e0f6583f48 100644 --- a/tests/notification/fixtures/submit_post_notification.type.topic.xml +++ b/tests/notification/fixtures/submit_post_notification.type.topic.xml @@ -106,28 +106,28 @@ <value>notification.type.topic</value> <value>0</value> <value>2</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.topic</value> <value>0</value> <value>6</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.topic</value> <value>0</value> <value>7</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> <row> <value>notification.type.topic</value> <value>0</value> <value>8</value> - <value></value> + <value>notification.method.board</value> <value>1</value> </row> </table> diff --git a/tests/notification/group_request_test.php b/tests/notification/group_request_test.php index 0d1bda95ce..d16e198861 100644 --- a/tests/notification/group_request_test.php +++ b/tests/notification/group_request_test.php @@ -40,8 +40,6 @@ class phpbb_notification_group_request_test extends phpbb_tests_notification_bas include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); include_once($phpbb_root_path . 'includes/functions_content.' . $phpEx); - set_config(false, false, false, $this->config); - $this->container->set('groupposition.legend', new \phpbb\groupposition\legend( $this->db, $this->user @@ -51,8 +49,14 @@ class phpbb_notification_group_request_test extends phpbb_tests_notification_bas $this->user, $this->cache->get_driver() )); + $this->container->set('group_helper', new \phpbb\group\helper( + new \phpbb\language\language( + new phpbb\language\language_file_loader($phpbb_root_path, $phpEx) + ) + )); $phpbb_dispatcher = new phpbb_mock_event_dispatcher; - $phpbb_log = new \phpbb\log\null(); + $phpbb_log = new \phpbb\log\dummy(); + $this->get_test_case_helpers()->set_s9e_services(); // Now on to the actual test diff --git a/tests/notification/manager_helper.php b/tests/notification/manager_helper.php index 75b7275d3a..2e8699e1e0 100644 --- a/tests/notification/manager_helper.php +++ b/tests/notification/manager_helper.php @@ -37,35 +37,4 @@ class phpbb_notification_manager_helper extends \phpbb\notification\manager $this->auth = $auth; $this->config = $config; } - - /** - * Helper to get the notifications item type class and set it up - */ - public function get_item_type_class($item_type, $data = array()) - { - $item_parts = explode('.', $item_type); - $item_type = 'phpbb\notification\type\\' . array_pop($item_parts); - - $item = new $item_type($this->user_loader, $this->db, $this->cache->get_driver(), $this->user, $this->auth, $this->config, $this->phpbb_root_path, $this->php_ext, $this->notification_types_table, $this->notifications_table, $this->user_notifications_table); - - $item->set_notification_manager($this); - - $item->set_initial_data($data); - - return $item; - } - - /** - * Helper to get the notifications method class and set it up - */ - public function get_method_class($method_name) - { - $method_name = 'phpbb\notification\method\\' . $method_name; - - $method = new $method_name($this->user_loader, $this->db, $this->cache->get_driver(), $this->user, $this->auth, $this->config, $this->phpbb_root_path, $this->php_ext, $this->notification_types_table, $this->notifications_table, $this->user_notifications_table); - - $method->set_notification_manager($this); - - return $method; - } } diff --git a/tests/notification/notification_test.php b/tests/notification/notification_test.php index 79fa5338c4..ec42aa193c 100644 --- a/tests/notification/notification_test.php +++ b/tests/notification/notification_test.php @@ -29,7 +29,7 @@ class phpbb_notification_test extends phpbb_tests_notification_base $quote_type_id = $this->notifications->get_notification_type_id('notification.type.quote'); $test_type_id = $this->notifications->get_notification_type_id('test'); - $this->assertEquals(array( + self::assertEquals(array( 'test' => $test_type_id, 'notification.type.quote' => $quote_type_id, 'notification.type.post' => $post_type_id, @@ -40,13 +40,13 @@ class phpbb_notification_test extends phpbb_tests_notification_base 'notification.type.post', ) )); - $this->assertEquals($quote_type_id, $this->notifications->get_notification_type_id('notification.type.quote')); + self::assertEquals($quote_type_id, $this->notifications->get_notification_type_id('notification.type.quote')); try { - $this->assertEquals(false, $this->notifications->get_notification_type_id('fail')); + self::assertEquals(false, $this->notifications->get_notification_type_id('fail')); - $this->fail('Non-existent type should throw an exception'); + self::fail('Non-existent type should throw an exception'); } catch (Exception $e) {} } @@ -55,15 +55,15 @@ class phpbb_notification_test extends phpbb_tests_notification_base { $subscription_types = $this->notifications->get_subscription_types(); - $this->assertArrayHasKey('NOTIFICATION_GROUP_MISCELLANEOUS', $subscription_types); - $this->assertArrayHasKey('NOTIFICATION_GROUP_POSTING', $subscription_types); + self::assertArrayHasKey('NOTIFICATION_GROUP_MISCELLANEOUS', $subscription_types); + self::assertArrayHasKey('NOTIFICATION_GROUP_POSTING', $subscription_types); - $this->assertArrayHasKey('notification.type.bookmark', $subscription_types['NOTIFICATION_GROUP_POSTING']); - $this->assertArrayHasKey('notification.type.post', $subscription_types['NOTIFICATION_GROUP_POSTING']); - $this->assertArrayHasKey('notification.type.quote', $subscription_types['NOTIFICATION_GROUP_POSTING']); - $this->assertArrayHasKey('notification.type.topic', $subscription_types['NOTIFICATION_GROUP_POSTING']); + self::assertArrayHasKey('notification.type.bookmark', $subscription_types['NOTIFICATION_GROUP_POSTING']); + self::assertArrayHasKey('notification.type.post', $subscription_types['NOTIFICATION_GROUP_POSTING']); + self::assertArrayHasKey('notification.type.quote', $subscription_types['NOTIFICATION_GROUP_POSTING']); + self::assertArrayHasKey('notification.type.topic', $subscription_types['NOTIFICATION_GROUP_POSTING']); - $this->assertArrayHasKey('notification.type.pm', $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']); + self::assertArrayHasKey('notification.type.pm', $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']); //get_subscription_types //get_subscription_methods @@ -72,33 +72,33 @@ class phpbb_notification_test extends phpbb_tests_notification_base public function test_subscriptions() { $expected_subscriptions = array( - 'notification.type.post' => array(''), - 'notification.type.topic' => array(''), - 'notification.type.quote' => array(''), - 'notification.type.bookmark' => array(''), - 'test' => array(''), - 'notification.type.pm' => array(''), + 'notification.type.post' => array('notification.method.board'), + 'notification.type.topic' => array('notification.method.board'), + 'notification.type.quote' => array('notification.method.board'), + 'notification.type.bookmark' => array('notification.method.board'), + 'test' => array('notification.method.board'), + 'notification.type.pm' => array('notification.method.board'), ); $subscriptions = $this->notifications->get_global_subscriptions(2); - foreach ($expected_subscriptions as $item_type => $methods) { + self::assertArrayHasKey($item_type, $subscriptions); $this->assert_array_content_equals($methods, $subscriptions[$item_type]); } foreach ($subscriptions as $item_type => $methods) { - $this->assert_array_content_equals($methods, $expected_subscriptions[$item_type]); + $this->assert_array_content_equals($methods, $expected_subscriptions[$item_type]); } - $this->notifications->delete_subscription('notification.type.post', 0, '', 2); + $this->notifications->delete_subscription('notification.type.post', 0, 'notification.method.board', 2); - $this->assertArrayNotHasKey('notification.type.post', $this->notifications->get_global_subscriptions(2)); + self::assertArrayNotHasKey('notification.type.post', $this->notifications->get_global_subscriptions(2)); - $this->notifications->add_subscription('notification.type.post', 0, '', 2); + $this->notifications->add_subscription('notification.type.post', 0, 'notification.method.board', 2); - $this->assertArrayHasKey('notification.type.post', $this->notifications->get_global_subscriptions(2)); + self::assertArrayHasKey('notification.type.post', $this->notifications->get_global_subscriptions(2)); } public function test_notifications() @@ -124,11 +124,11 @@ class phpbb_notification_test extends phpbb_tests_notification_base 'user_id' => 0, ))); - $this->assertEquals(array( + self::assertEquals(array( 'notifications' => array(), 'unread_count' => 0, 'total_count' => 0, - ), $this->notifications->load_notifications(array( + ), $this->notifications->load_notifications('notification.method.board', array( 'count_unread' => true, ))); diff --git a/tests/notification/submit_post_base.php b/tests/notification/submit_post_base.php index 5e770f71c9..14ca4499d2 100644 --- a/tests/notification/submit_post_base.php +++ b/tests/notification/submit_post_base.php @@ -11,6 +11,10 @@ * */ +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; + require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php'; @@ -50,7 +54,7 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c { parent::setUp(); - global $auth, $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $user, $request, $phpEx, $phpbb_root_path; + global $auth, $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $lang, $user, $request, $phpEx, $phpbb_root_path, $user_loader; // Database $this->db = $this->new_dbal(); @@ -69,12 +73,15 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c ))); // Config - $config = new \phpbb\config\config(array('num_topics' => 1,'num_posts' => 1,)); - set_config(null, null, null, $config); - set_config_count(null, null, null, $config); + $config = new \phpbb\config\config(array( + 'num_topics' => 1, + 'num_posts' => 1, + 'allow_board_notifications' => true, + )); + $cache_driver = new \phpbb\cache\driver\dummy(); $cache = new \phpbb\cache\service( - new \phpbb\cache\driver\null(), + $cache_driver, $config, $db, $phpbb_root_path, @@ -84,8 +91,14 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c // Event dispatcher $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); + // Language + $lang = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + // User - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $user = $this->getMock('\phpbb\user', array(), array( + $lang, + '\phpbb\datetime' + )); $user->ip = ''; $user->data = array( 'user_id' => 2, @@ -98,34 +111,47 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c $type_cast_helper = $this->getMock('\phpbb\request\type_cast_helper_interface'); $request = $this->getMock('\phpbb\request\request'); - // Container - $phpbb_container = new phpbb_mock_container_builder(); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE)); - $user_loader = new \phpbb\user_loader($db, $phpbb_root_path, $phpEx, USERS_TABLE); + // Container + $phpbb_container = new ContainerBuilder(); + $loader = new YamlFileLoader($phpbb_container, new FileLocator(__DIR__ . '/fixtures')); + $loader->load('services_notification.yml'); + $phpbb_container->set('user_loader', $user_loader); + $phpbb_container->set('user', $user); + $phpbb_container->set('language', $lang); + $phpbb_container->set('config', $config); + $phpbb_container->set('dbal.conn', $db); + $phpbb_container->set('auth', $auth); + $phpbb_container->set('cache.driver', $cache_driver); + $phpbb_container->set('cache', $cache); + $phpbb_container->set('text_formatter.utils', new \phpbb\textformatter\s9e\utils()); + $phpbb_container->set('dispatcher', $phpbb_dispatcher); + $phpbb_container->setParameter('core.root_path', $phpbb_root_path); + $phpbb_container->setParameter('core.php_ext', $phpEx); + $phpbb_container->setParameter('tables.notifications', 'phpbb_notifications'); + $phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications'); + $phpbb_container->setParameter('tables.notification_types', 'phpbb_notification_types'); + $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE)); + $phpbb_container->compile(); + // Notification Types $notification_types = array('quote', 'bookmark', 'post', 'post_in_queue', 'topic', 'topic_in_queue', 'approve_topic', 'approve_post'); $notification_types_array = array(); foreach ($notification_types as $type) { - $class_name = '\phpbb\notification\type\\' . $type; - $class = new $class_name( - $user_loader, $db, $cache->get_driver(), $user, $auth, $config, - $phpbb_root_path, $phpEx, - NOTIFICATION_TYPES_TABLE, NOTIFICATIONS_TABLE, USER_NOTIFICATIONS_TABLE); - - $phpbb_container->set('notification.type.' . $type, $class); - + $class = $phpbb_container->get('notification.type.' . $type); $notification_types_array['notification.type.' . $type] = $class; } + // Methods Types + $notification_methods_array = array('notification.method.board' => $phpbb_container->get('notification.method.board')); + // Notification Manager - $phpbb_notifications = new \phpbb\notification\manager($notification_types_array, array(), - $phpbb_container, $user_loader, $config, $phpbb_dispatcher, $db, $cache, $user, - $phpbb_root_path, $phpEx, - NOTIFICATION_TYPES_TABLE, NOTIFICATIONS_TABLE, USER_NOTIFICATIONS_TABLE); + $phpbb_notifications = new \phpbb\notification\manager($notification_types_array, $notification_methods_array, + $phpbb_container, $user_loader, $phpbb_dispatcher, $db, $cache, $lang, $user, + NOTIFICATION_TYPES_TABLE, USER_NOTIFICATIONS_TABLE); $phpbb_container->set('notification_manager', $phpbb_notifications); } diff --git a/tests/notification/submit_post_type_quote_test.php b/tests/notification/submit_post_type_quote_test.php index 61e3840773..3fab8c05ba 100644 --- a/tests/notification/submit_post_type_quote_test.php +++ b/tests/notification/submit_post_type_quote_test.php @@ -51,6 +51,9 @@ class phpbb_notification_submit_post_type_quote_test extends phpbb_notification_ */ public function submit_post_data() { + // The new mock container is needed because the data providers may be executed before phpunit call setUp() + $parser = $this->get_test_case_helpers()->set_s9e_services(new phpbb_mock_container_builder())->get('text_formatter.parser'); + return array( /** * Normal post @@ -65,15 +68,15 @@ class phpbb_notification_submit_post_type_quote_test extends phpbb_notification_ */ array( array( - 'message' => implode(' ', array( - '[quote="poster":uid]poster should not be notified[/quote:uid]', - '[quote="test":uid]test should be notified[/quote:uid]', - '[quote="unauthorized":uid]unauthorized to read, should not receive a notification[/quote:uid]', - '[quote="notified":uid]already notified, should not receive a new notification[/quote:uid]', - '[quote="disabled":uid]option disabled, should not receive a notification[/quote:uid]', - '[quote="default":uid]option set to default, should receive a notification[/quote:uid]', - '[quote="doesn\'t exist":uid]user does not exist, should not receive a notification[/quote:uid]', - )), + 'message' => $parser->parse(implode(' ', array( + '[quote="poster"]poster should not be notified[/quote]', + '[quote="test"]test should be notified[/quote]', + '[quote="unauthorized"]unauthorized to read, should not receive a notification[/quote]', + '[quote="notified"]already notified, should not receive a new notification[/quote]', + '[quote="disabled"]option disabled, should not receive a notification[/quote]', + '[quote="default"]option set to default, should receive a notification[/quote]', + '[quote="doesn\'t exist"]user does not exist, should not receive a notification[/quote]', + ))), 'bbcode_uid' => 'uid', ), array( @@ -94,15 +97,15 @@ class phpbb_notification_submit_post_type_quote_test extends phpbb_notification_ */ array( array( - 'message' => implode(' ', array( - '[quote="poster":uid]poster should not be notified[/quote:uid]', - '[quote="test":uid]test should be notified[/quote:uid]', - '[quote="unauthorized":uid]unauthorized to read, should not receive a notification[/quote:uid]', - '[quote="notified":uid]already notified, should not receive a new notification[/quote:uid]', - '[quote="disabled":uid]option disabled, should not receive a notification[/quote:uid]', - '[quote="default":uid]option set to default, should receive a notification[/quote:uid]', - '[quote="doesn\'t exist":uid]user does not exist, should not receive a notification[/quote:uid]', - )), + 'message' => $parser->parse(implode(' ', array( + '[quote="poster"]poster should not be notified[/quote]', + '[quote="test"]test should be notified[/quote]', + '[quote="unauthorized"]unauthorized to read, should not receive a notification[/quote]', + '[quote="notified"]already notified, should not receive a new notification[/quote]', + '[quote="disabled"]option disabled, should not receive a notification[/quote]', + '[quote="default"]option set to default, should receive a notification[/quote]', + '[quote="doesn\'t exist"]user does not exist, should not receive a notification[/quote]', + ))), 'bbcode_uid' => 'uid', 'force_approved_state' => false, ), diff --git a/tests/notification/submit_post_type_topic_test.php b/tests/notification/submit_post_type_topic_test.php index c095fbc4ba..f14f305517 100644 --- a/tests/notification/submit_post_type_topic_test.php +++ b/tests/notification/submit_post_type_topic_test.php @@ -42,7 +42,7 @@ class phpbb_notification_submit_post_type_topic_test extends phpbb_notification_ ), ))); - $phpbb_log = $this->getMock('\phpbb\log\null'); + $phpbb_log = $this->getMock('\phpbb\log\dummy'); } /** diff --git a/tests/notification/user_list_trim_test.php b/tests/notification/user_list_trim_test.php index c43eff729c..9f6eb492f6 100644 --- a/tests/notification/user_list_trim_test.php +++ b/tests/notification/user_list_trim_test.php @@ -33,11 +33,9 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case $db = $this->new_dbal(); $config = new \phpbb\config\config(array()); - set_config(null, null, null, $config); - set_config_count(null, null, null, $config); $cache = new \phpbb\cache\service( - new \phpbb\cache\driver\null(), + new \phpbb\cache\driver\dummy(), $config, $db, $phpbb_root_path, @@ -53,15 +51,17 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case array('u_viewprofile', 1, false), ))); - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->data = array('user_lang' => 'en'); - $user->add_lang('common'); + $lang->add_lang('common'); $user_loader = new phpbb\user_loader($db, $phpbb_root_path, $phpEx, USERS_TABLE); $user_loader->load_users(array(2, 3, 4, 5, 6)); $this->notification = new phpbb_mock_notification_type_post( - $user_loader, null, null, $user, null, null, $phpbb_root_path, $phpEx, null, null, null + $user_loader, null, null, $lang, $user, null, null, $phpbb_root_path, $phpEx, null, null ); } @@ -73,7 +73,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case 'topic_title' => 'Test', 'poster_id' => 2, 'post_username' => 'A', - 'responders' => null, + 'responders' => null, ), '<strong>Reply</strong> from A in topic:', ), @@ -84,7 +84,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case 'post_username' => 'A', 'responders' => array( array('username' => '', 'poster_id' => 3), - ), + ), ), '<strong>Reply</strong> from A and <span class="username">B</span> in topic:', ), @@ -96,7 +96,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case 'responders' => array( array('username' => '', 'poster_id' => 3), array('username' => '', 'poster_id' => 4), - ), + ), ), '<strong>Reply</strong> from A, <span class="username">B</span>, and <span class="username">C</span> in topic:', ), @@ -109,7 +109,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case array('username' => '', 'poster_id' => 3), array('username' => '', 'poster_id' => 4), array('username' => '', 'poster_id' => 5), - ), + ), ), '<strong>Reply</strong> from A, <span class="username">B</span>, <span class="username">C</span>, and <span class="username">D</span> in topic:', ), @@ -123,7 +123,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case array('username' => '', 'poster_id' => 4), array('username' => '', 'poster_id' => 5), array('username' => '', 'poster_id' => 6), - ), + ), ), '<strong>Reply</strong> from A, <span class="username">B</span>, <span class="username">C</span>, and 2 others in topic:', ), diff --git a/tests/pagination/config/routing.yml b/tests/pagination/config/test/routing/environment.yml index 2ce082c9d1..2ce082c9d1 100644 --- a/tests/pagination/config/routing.yml +++ b/tests/pagination/config/test/routing/environment.yml diff --git a/tests/pagination/pagination_test.php b/tests/pagination/pagination_test.php index ea6dd999c3..6a3b46cdae 100644 --- a/tests/pagination/pagination_test.php +++ b/tests/pagination/pagination_test.php @@ -26,27 +26,27 @@ class phpbb_pagination_pagination_test extends phpbb_template_template_test_case { parent::setUp(); - global $phpbb_dispatcher; + global $phpbb_dispatcher, $phpbb_root_path, $phpEx; $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $this->user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $this->user->expects($this->any()) ->method('lang') ->will($this->returnCallback(array($this, 'return_callback_implode'))); - $filesystem = new \phpbb\filesystem(); + $filesystem = new \phpbb\filesystem\filesystem(); $manager = new phpbb_mock_extension_manager(dirname(__FILE__) . '/', array()); - $finder = new \phpbb\finder( - $filesystem, - dirname(__FILE__) . '/', - new phpbb_mock_cache() - ); - $finder->set_extensions(array_keys($manager->all_enabled())); $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1')); - $provider = new \phpbb\controller\provider(); - $provider->find_routing_files($finder); - $provider->find(dirname(__FILE__) . '/'); + + $loader = new \Symfony\Component\Routing\Loader\YamlFileLoader( + new \phpbb\routing\file_locator($filesystem, dirname(__FILE__) . '/') + ); + $resources_locator = new \phpbb\routing\resources_locator\default_resources_locator(dirname(__FILE__) . '/', PHPBB_ENVIRONMENT, $manager); + $router = new phpbb_mock_router(new phpbb_mock_container_builder(), $resources_locator, $loader, dirname(__FILE__) . '/', 'php', PHPBB_ENVIRONMENT); $request = new phpbb_mock_request(); $request->overwrite('SCRIPT_NAME', '/app.php', \phpbb\request\request_interface::SERVER); @@ -57,7 +57,8 @@ class phpbb_pagination_pagination_test extends phpbb_template_template_test_case $request ); - $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $provider, $manager, $symfony_request, $request, $filesystem, '', 'php', dirname(__FILE__) . '/'); + $this->routing_helper = new \phpbb\routing\helper($this->config, $router, $symfony_request, $request, $filesystem, '', 'php'); + $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $symfony_request, $request, $this->routing_helper); $this->pagination = new \phpbb\pagination($this->template, $this->user, $this->helper, $phpbb_dispatcher); } diff --git a/tests/path_helper/path_helper_test.php b/tests/path_helper/path_helper_test.php index 73f0e6bafc..49dd40fbec 100644 --- a/tests/path_helper/path_helper_test.php +++ b/tests/path_helper/path_helper_test.php @@ -21,14 +21,14 @@ class phpbb_path_helper_test extends phpbb_test_case { parent::setUp(); - $filesystem = new \phpbb\filesystem(); + $filesystem = new \phpbb\filesystem\filesystem(); $this->set_phpbb_root_path($filesystem); $this->path_helper = new \phpbb\path_helper( new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + new \phpbb\filesystem\filesystem(), $this->getMock('\phpbb\request\request'), $this->phpbb_root_path, 'php' @@ -56,7 +56,7 @@ class phpbb_path_helper_test extends phpbb_test_case public function basic_update_web_root_path_data() { - $filesystem = new \phpbb\filesystem(); + $filesystem = new \phpbb\filesystem\filesystem(); $this->set_phpbb_root_path($filesystem); return array( @@ -90,7 +90,7 @@ class phpbb_path_helper_test extends phpbb_test_case public function update_web_root_path_data() { - $this->set_phpbb_root_path(new \phpbb\filesystem()); + $this->set_phpbb_root_path(new \phpbb\filesystem\filesystem()); return array( array( @@ -135,6 +135,43 @@ class phpbb_path_helper_test extends phpbb_test_case '/phpbb3-fork/phpBB/app.php', './../', ), + + // No correction if the path is already prepend by the web root path + array( + './../' . $this->phpbb_root_path . 'test.php', + '//', + null, + null, + '', + ), + array( + './../' . $this->phpbb_root_path . 'test.php', + '//', + 'foo/bar.php', + 'bar.php', + '', + ), + array( + './../../' . $this->phpbb_root_path . 'test.php', + '/foo/template', + '/phpbb3-fork/phpBB/app.php/foo/template', + '/phpbb3-fork/phpBB/app.php', + '', + ), + array( + './../' . $this->phpbb_root_path . 'test.php', + '/foo/template', + '/phpbb3-fork/phpBB/foo/template', + '/phpbb3-fork/phpBB/app.php', + '', + ), + array( + './../'.$this->phpbb_root_path . 'test.php', + '/', + '/phpbb3-fork/phpBB/app.php/', + '/phpbb3-fork/phpBB/app.php', + '', + ), ); } @@ -158,7 +195,7 @@ class phpbb_path_helper_test extends phpbb_test_case $path_helper = new \phpbb\path_helper( $symfony_request, - new \phpbb\filesystem(), + new \phpbb\filesystem\filesystem(), $this->getMock('\phpbb\request\request'), $this->phpbb_root_path, 'php' diff --git a/tests/plupload/plupload_test.php b/tests/plupload/plupload_test.php index 2f47bf2b39..3312f4d0a0 100644 --- a/tests/plupload/plupload_test.php +++ b/tests/plupload/plupload_test.php @@ -34,6 +34,10 @@ class phpbb_plupload_test extends phpbb_test_case */ public function test_generate_resize_string($config_width, $config_height, $expected) { + global $phpbb_root_path, $phpEx; + + $lang = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $config = new \phpbb\config\config(array( 'img_max_width' => $config_width, 'img_max_height' => $config_height, @@ -43,8 +47,8 @@ class phpbb_plupload_test extends phpbb_test_case '', $config, new phpbb_mock_request, - new \phpbb\user('\phpbb\datetime'), - new \phpbb\php\ini, + new \phpbb\user($lang, '\phpbb\datetime'), + new \bantu\IniGetWrapper\IniGetWrapper, new \phpbb\mimetype\guesser(array(new \phpbb\mimetype\extension_guesser)) ); diff --git a/tests/privmsgs/delete_user_pms_test.php b/tests/privmsgs/delete_user_pms_test.php index 0f061e9784..9d6ba7a917 100644 --- a/tests/privmsgs/delete_user_pms_test.php +++ b/tests/privmsgs/delete_user_pms_test.php @@ -85,12 +85,14 @@ class phpbb_privmsgs_delete_user_pms_test extends phpbb_database_test_case */ public function test_delete_user_pms($delete_user, $remaining_privmsgs, $remaining_privmsgs_to) { - global $db, $phpbb_container; + global $db, $phpbb_container, $phpbb_root_path; $db = $this->new_dbal(); $phpbb_container = new phpbb_mock_container_builder(); $phpbb_container->set('notification_manager', new phpbb_mock_notification_manager()); + // Works as a workaround for tests + $phpbb_container->set('attachment.manager', new \phpbb\attachment\delete(new \phpbb\config\config(array()), $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path)); phpbb_delete_user_pms($delete_user); diff --git a/tests/profilefields/type_bool_test.php b/tests/profilefields/type_bool_test.php index 41c40ddb4b..10239172c3 100644 --- a/tests/profilefields/type_bool_test.php +++ b/tests/profilefields/type_bool_test.php @@ -25,7 +25,12 @@ class phpbb_profilefield_type_bool_test extends phpbb_test_case */ public function setUp() { - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + global $phpbb_root_path, $phpEx; + + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $user->expects($this->any()) ->method('lang') ->will($this->returnCallback(array($this, 'return_callback_implode'))); diff --git a/tests/profilefields/type_date_test.php b/tests/profilefields/type_date_test.php index 123955198e..e0807b2f9b 100644 --- a/tests/profilefields/type_date_test.php +++ b/tests/profilefields/type_date_test.php @@ -25,7 +25,12 @@ class phpbb_profilefield_type_date_test extends phpbb_test_case */ public function setUp() { - $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + global $phpbb_root_path, $phpEx; + + $this->user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $this->user->expects($this->any()) ->method('lang') ->will($this->returnCallback(array($this, 'return_callback_implode'))); diff --git a/tests/profilefields/type_dropdown_test.php b/tests/profilefields/type_dropdown_test.php index 3845a8e96b..ab02353fb9 100644 --- a/tests/profilefields/type_dropdown_test.php +++ b/tests/profilefields/type_dropdown_test.php @@ -25,7 +25,12 @@ class phpbb_profilefield_type_dropdown_test extends phpbb_test_case */ public function setUp() { - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + global $phpbb_root_path, $phpEx; + + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $user->expects($this->any()) ->method('lang') ->will($this->returnCallback(array($this, 'return_callback_implode'))); diff --git a/tests/profilefields/type_googleplus_test.php b/tests/profilefields/type_googleplus_test.php index f3db6ef01f..6faf939231 100644 --- a/tests/profilefields/type_googleplus_test.php +++ b/tests/profilefields/type_googleplus_test.php @@ -21,7 +21,11 @@ class phpbb_profilefield_type_googleplus_test extends phpbb_test_case { parent::setUp(); - $user = new \phpbb\user('\phpbb\datetime'); + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->add_lang('ucp'); $request = $this->getMock('\phpbb\request\request'); $template = $this->getMock('\phpbb\template\template'); diff --git a/tests/profilefields/type_int_test.php b/tests/profilefields/type_int_test.php index 07b22525e2..33f3f575c8 100644 --- a/tests/profilefields/type_int_test.php +++ b/tests/profilefields/type_int_test.php @@ -24,7 +24,12 @@ class phpbb_profilefield_type_int_test extends phpbb_test_case */ public function setUp() { - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + global $phpbb_root_path, $phpEx; + + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $user->expects($this->any()) ->method('lang') ->will($this->returnCallback(array($this, 'return_callback_implode'))); diff --git a/tests/profilefields/type_string_test.php b/tests/profilefields/type_string_test.php index 0417afbfab..447ab32a00 100644 --- a/tests/profilefields/type_string_test.php +++ b/tests/profilefields/type_string_test.php @@ -28,9 +28,12 @@ class phpbb_profilefield_type_string_test extends phpbb_test_case */ public function setUp() { - global $request, $user, $cache; + global $request, $user, $cache, $phpbb_root_path, $phpEx; - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $cache = new phpbb_mock_cache; $user->expects($this->any()) ->method('lang') diff --git a/tests/profilefields/type_url_test.php b/tests/profilefields/type_url_test.php index cc37f04f30..a0f93fe1f6 100644 --- a/tests/profilefields/type_url_test.php +++ b/tests/profilefields/type_url_test.php @@ -26,7 +26,12 @@ class phpbb_profilefield_type_url_test extends phpbb_test_case */ public function setUp() { - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + global $phpbb_root_path, $phpEx; + + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $user->expects($this->any()) ->method('lang') ->will($this->returnCallback(array($this, 'return_callback_implode'))); diff --git a/tests/regex/censor_test.php b/tests/regex/censor_test.php index 50c6778c8c..5625b0020b 100644 --- a/tests/regex/censor_test.php +++ b/tests/regex/censor_test.php @@ -37,17 +37,7 @@ class phpbb_regex_censor_test extends phpbb_test_case */ public function test_censor_unicode($pattern, $subject) { - $regex = get_censor_preg_expression($pattern, true); - - $this->assertRegExp($regex, $subject); - } - - /** - * @dataProvider censor_test_data - */ - public function test_censor_no_unicode($pattern, $subject) - { - $regex = get_censor_preg_expression($pattern, false); + $regex = get_censor_preg_expression($pattern); $this->assertRegExp($regex, $subject); } diff --git a/tests/request/request_var_test.php b/tests/request/request_var_test.php index 67712eb6c8..b409e5ef25 100644 --- a/tests/request/request_var_test.php +++ b/tests/request/request_var_test.php @@ -11,7 +11,7 @@ * */ -require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_compatibility.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php'; class phpbb_request_var_test extends phpbb_test_case diff --git a/tests/security/base.php b/tests/security/base.php index 330408b448..d2abdbc362 100644 --- a/tests/security/base.php +++ b/tests/security/base.php @@ -46,10 +46,12 @@ abstract class phpbb_security_test_base extends phpbb_test_case $request = new phpbb_mock_request(array(), array(), array(), $this->server); $symfony_request = new \phpbb\symfony_request($request); - $phpbb_filesystem = new \phpbb\filesystem(); + $phpbb_filesystem = new \phpbb\filesystem\filesystem(); // Set no user and trick a bit to circumvent errors - $user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->lang = true; $user->browser = $this->server['HTTP_USER_AGENT']; $user->referer = ''; diff --git a/tests/security/redirect_test.php b/tests/security/redirect_test.php index a88fc63858..62781f3ee6 100644 --- a/tests/security/redirect_test.php +++ b/tests/security/redirect_test.php @@ -67,7 +67,7 @@ class phpbb_security_redirect_test extends phpbb_security_test_base new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + new \phpbb\filesystem\filesystem(), $this->getMock('\phpbb\request\request'), $this->phpbb_root_path, 'php' diff --git a/tests/session/check_ban_test.php b/tests/session/check_ban_test.php index 561b7faf49..04da5f08b9 100644 --- a/tests/session/check_ban_test.php +++ b/tests/session/check_ban_test.php @@ -42,7 +42,10 @@ class phpbb_session_check_ban_test extends phpbb_session_test_case parent::setUp(); // Get session here so that config is mocked correctly $this->session = $this->session_factory->get_session($this->db); - global $cache, $config, $phpbb_root_path, $phpEx; + global $cache, $config, $phpbb_root_path, $phpEx, $phpbb_filesystem; + + $phpbb_filesystem = new \phpbb\filesystem\filesystem(); + $this->backup_cache = $cache; // Change the global cache object for this test because // the mock cache object does not hit the database as is needed diff --git a/tests/session/extract_page_test.php b/tests/session/extract_page_test.php index f0d1cdb60e..96445ef9b3 100644 --- a/tests/session/extract_page_test.php +++ b/tests/session/extract_page_test.php @@ -145,7 +145,7 @@ class phpbb_session_extract_page_test extends phpbb_session_test_case { global $symfony_request, $request, $phpbb_filesystem; - $phpbb_filesystem = new \phpbb\filesystem(); + $phpbb_filesystem = new \phpbb\filesystem\filesystem(); $server['HTTP_HOST'] = 'localhost'; $server['SERVER_NAME'] = 'localhost'; diff --git a/tests/session/testable_factory.php b/tests/session/testable_factory.php index 3e25286480..7819063505 100644 --- a/tests/session/testable_factory.php +++ b/tests/session/testable_factory.php @@ -81,10 +81,8 @@ class phpbb_session_testable_factory $this->cookies, $this->server_data ); - request_var(null, null, null, null, $request); $config = $this->config = new \phpbb\config\config($this->get_config_data()); - set_config(null, null, null, $config); $db = $dbal; @@ -96,6 +94,7 @@ class phpbb_session_testable_factory 'auth.provider.db', new phpbb_mock_auth_provider() ); + $phpbb_container->setParameter('core.environment', PHPBB_ENVIRONMENT); $provider_collection = new \phpbb\auth\provider_collection($phpbb_container, $config); $provider_collection->add('auth.provider.db'); $phpbb_container->set( diff --git a/tests/template/asset_test.php b/tests/template/asset_test.php new file mode 100644 index 0000000000..3d2fdd8959 --- /dev/null +++ b/tests/template/asset_test.php @@ -0,0 +1,49 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +use phpbb\template\asset; + +class phpbb_template_asset_test extends phpbb_test_case +{ + public function set_path_data() + { + return array( + // array(phpbb_root_path, given path, expected path), + array('.', 'foo/bar', 'foo/bar'), + array('../', 'foo/bar', 'foo/bar'), + array('./phpBB/', 'foo/bar', 'foo/bar'), + array('../', __DIR__ . '/foo/bar', '../' . basename(dirname(dirname(__DIR__))) . '/tests/template/foo/bar'), + array('./', __DIR__ . '/foo/bar', './tests/template/foo/bar'), + array('./phpBB/', __DIR__ . '/foo/bar', 'tests/template/foo/bar'), + ); + } + + /** + * @dataProvider set_path_data + */ + public function test_set_path($phpbb_root_path, $path, $expected) + { + $path_helper = $this->getMockBuilder('\phpbb\path_helper') + ->disableOriginalConstructor() + ->setMethods(array()) + ->getMock(); + + $path_helper->method('get_phpbb_root_path') + ->willReturn($phpbb_root_path); + + $asset = new asset('', $path_helper, new phpbb\filesystem\filesystem()); + + $asset->set_path($path, true); + $this->assertEquals($expected, $asset->get_path()); + } +} diff --git a/tests/template/includephp_test.php b/tests/template/includephp_test.php index fdddbef4f2..722e10e42d 100644 --- a/tests/template/includephp_test.php +++ b/tests/template/includephp_test.php @@ -39,8 +39,9 @@ class phpbb_template_includephp_test extends phpbb_template_template_test_case { global $phpbb_root_path; + $filesystem = new \phpbb\filesystem\filesystem(); $path_to_php = str_replace('\\', '/', dirname(__FILE__)) . '/templates/_dummy_include.php.inc'; - $this->assertTrue(phpbb_is_absolute($path_to_php)); + $this->assertTrue($filesystem->is_absolute_path($path_to_php)); $template_text = "Path is absolute.\n<!-- INCLUDEPHP $path_to_php -->"; $cache_dir = $phpbb_root_path . 'cache/'; diff --git a/tests/template/template_allfolder_test.php b/tests/template/template_allfolder_test.php index b4ad84e9c3..9a0f1f512e 100644 --- a/tests/template/template_allfolder_test.php +++ b/tests/template/template_allfolder_test.php @@ -28,13 +28,18 @@ class phpbb_template_allfolder_test extends phpbb_template_template_test_case $defaults = $this->config_defaults(); $config = new \phpbb\config\config(array_merge($defaults, $new_config)); - $this->user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $this->user = $user; + + $filesystem = new \phpbb\filesystem\filesystem(); $path_helper = new \phpbb\path_helper( new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + $filesystem, $this->getMock('\phpbb\request\request'), $phpbb_root_path, $phpEx @@ -51,9 +56,30 @@ class phpbb_template_allfolder_test extends phpbb_template_template_test_case ) ); + $container = new phpbb_mock_container_builder(); + $cache_path = $phpbb_root_path . 'cache/twig'; + $context = new \phpbb\template\context(); + $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), ''); + $twig = new \phpbb\template\twig\environment( + $config, + $filesystem, + $path_helper, + $container, + $cache_path, + $this->extension_manager, + $loader, + array( + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ) + ); + $this->template = new \phpbb\template\twig\twig($path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user)), $this->extension_manager); + $container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig)); + $this->template_path = $this->test_path . '/templates'; $this->ext_template_path = 'tests/extension/ext/vendor4/bar/styles/all/template'; - $this->template = new \phpbb\template\twig\twig($path_helper, $config, $this->user, new \phpbb\template\context(), $this->extension_manager); $this->template->set_custom_style('all', array($this->template_path, $this->ext_template_path)); } } diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index c415c969fe..54e08652a1 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -138,16 +138,40 @@ Zeta test event in all', $this->extension_manager = new phpbb_mock_filesystem_extension_manager( dirname(__FILE__) . "/datasets/$dataset/" ); + + $filesystem = new \phpbb\filesystem\filesystem(); $path_helper = new \phpbb\path_helper( new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + new \phpbb\filesystem\filesystem(), $this->getMock('\phpbb\request\request'), $phpbb_root_path, $phpEx ); - $this->template = new \phpbb\template\twig\twig($path_helper, $config, $user, new \phpbb\template\context, $this->extension_manager); + + $container = new phpbb_mock_container_builder(); + $cache_path = $phpbb_root_path . 'cache/twig'; + $context = new \phpbb\template\context(); + $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), ''); + $twig = new \phpbb\template\twig\environment( + $config, + $filesystem, + $path_helper, + $container, + $cache_path, + $this->extension_manager, + $loader, + array( + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ) + ); + $this->template = new \phpbb\template\twig\twig($path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user)), $this->extension_manager); + $container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig)); + $this->template->set_custom_style(((!empty($style_names)) ? $style_names : 'silver'), array($this->template_path)); } } diff --git a/tests/template/template_includecss_test.php b/tests/template/template_includecss_test.php index b025cd21d5..ac62e820ae 100644 --- a/tests/template/template_includecss_test.php +++ b/tests/template/template_includecss_test.php @@ -15,6 +15,12 @@ require_once dirname(__FILE__) . '/template_test_case_with_tree.php'; class phpbb_template_template_includecss_test extends phpbb_template_template_test_case_with_tree { + /** @var \phpbb\path_helper */ + protected $phpbb_path_helper; + + /** @var string */ + protected $parent_template_path; + protected function setup_engine(array $new_config = array()) { global $phpbb_root_path, $phpEx, $user; @@ -22,11 +28,13 @@ class phpbb_template_template_includecss_test extends phpbb_template_template_te $defaults = $this->config_defaults(); $config = new \phpbb\config\config(array_merge($defaults, $new_config)); + $filesystem = new \phpbb\filesystem\filesystem(); + $this->phpbb_path_helper = new \phpbb\path_helper( new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + $filesystem, $this->getMock('\phpbb\request\request'), $phpbb_root_path, $phpEx @@ -34,11 +42,33 @@ class phpbb_template_template_includecss_test extends phpbb_template_template_te $this->template_path = $this->test_path . '/templates'; $this->parent_template_path = $this->test_path . '/parent_templates'; + $container = new phpbb_mock_container_builder(); + $cache_path = $phpbb_root_path . 'cache/twig'; + $context = new \phpbb\template\context(); + $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), ''); + $twig = new \phpbb\template\twig\environment( + $config, + $filesystem, + $this->phpbb_path_helper, + $container, + $cache_path, + null, + $loader, + array( + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ) + ); $this->template = new phpbb\template\twig\twig( $this->phpbb_path_helper, $config, - $user, - new phpbb\template\context(), + $context, + $twig, + $cache_path, + $this->user, + array(new \phpbb\template\twig\extension($context, $this->user)), new phpbb_mock_extension_manager( dirname(__FILE__) . '/', array( @@ -50,6 +80,7 @@ class phpbb_template_template_includecss_test extends phpbb_template_template_te ) ) ); + $container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig)); $this->template->set_custom_style('tests', array($this->template_path, $this->parent_template_path)); } diff --git a/tests/template/template_test.php b/tests/template/template_test.php index 0bbfe3848d..33dc4ca551 100644 --- a/tests/template/template_test.php +++ b/tests/template/template_test.php @@ -130,6 +130,34 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "loop\nloop\nloop\nloop\nloop#0-block#0\nloop#0-block#1\nloop#1-block#0\nloop#1-block#1", ), array( + 'loop_twig.html', + array(), + array(), + array(), + "noloop\nnoloop", + ), + array( + 'loop_twig.html', + array(), + array('test_loop' => array(array())), + array(), + "loop\nloop", + ), + array( + 'loop_twig.html', + array(), + array('test_loop' => array(array(), array()), 'test_loop.block' => array(array())), + array(), + "loop\nloop\nloop\nloop", + ), + array( + 'loop_twig.html', + array(), + array('test_loop' => array(array(), array()), 'test_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('test_loop' => array(array('VARIABLE' => 'x'))), @@ -151,6 +179,27 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast\n0 - c\n1 - c\nlast inner", ), array( + 'loop_vars_twig.html', + array(), + array('test_loop' => array(array('VARIABLE' => 'x'))), + array(), + "first\n0 - a\nx - b\nset\nlast", + ), + array( + 'loop_vars_twig.html', + array(), + array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y'))), + array(), + "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast", + ), + array( + 'loop_vars_twig.html', + array(), + array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())), + array(), + "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast\n0 - c\n1 - c\nlast inner", + ), + array( 'loop_advanced.html', array(), array('test_loop' => array(array(), array(), array(), array(), array(), array(), array())), @@ -158,6 +207,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "101234561\nx\n101234561\nx\n101234561\nx\n1234561\nx\n1\nx\n101\nx\n234\nx\n10\nx\n561\nx\n561", ), array( + 'loop_advanced_twig.html', + array(), + array('test_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( 'loop_nested2.html', array(), array('outer' => array(array(), array()), 'outer.middle' => array(array(), array())), @@ -165,6 +221,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "o0o1m01m11", ), array( + 'loop_nested2_twig.html', + array(), + array('outer' => array(array(), array()), 'outer.middle' => array(array(), array())), + array(), + "o0o1m01m11", + ), + array( 'define.html', array(), array('test_loop' => array(array(), array(), array(), array(), array(), array(), array()), 'test' => array(array()), 'test.deep' => array(array()), 'test.deep.defines' => array(array())), @@ -244,6 +307,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case '', ), array( + 'loop_vars_twig.html', + array(), + array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())), + array('test_loop'), + '', + ), + array( 'include_define_variable.html', array('VARIABLE' => 'variable.html'), array(), @@ -275,6 +345,15 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "noloop\nnoloop", ), array( + // Just like a regular loop but the name begins + // with an underscore + 'loop_underscore_twig.html', + array(), + array(), + array(), + "noloop\nnoloop", + ), + array( 'lang.html', array(), array(), @@ -286,7 +365,7 @@ class phpbb_template_template_test extends phpbb_template_template_test_case array(), array(), array(), - "Value'\n1 O'Clock\nValue\'\n1 O\'Clock", + "Value'\n1 O'Clock\nValue\\x27\n1\\x20O\\x27Clock", array('VARIABLE' => "Value'", '1_VARIABLE' => "1 O'Clock"), ), array( @@ -297,6 +376,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "top-level content", ), array( + 'loop_nested_multilevel_ref_twig.html', + array(), + array(), + array(), + "top-level content", + ), + array( 'loop_nested_multilevel_ref.html', array(), array('outer' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'outer.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))), @@ -304,6 +390,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "top-level content\nouter x\nouter y\ninner z\nfirst row\n\ninner zz", ), array( + 'loop_nested_multilevel_ref_twig.html', + array(), + array('outer' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'outer.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))), + array(), + "top-level content\nouter x\nouter y\ninner z\nfirst row\n\ninner zz", + ), + array( 'loop_nested_deep_multilevel_ref.html', array(), array('outer' => array(array()), 'outer.middle' => array(array()), 'outer.middle.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))), @@ -311,6 +404,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "top-level content\nouter\nmiddle\ninner z\nfirst row of 2 in inner\n\ninner zz", ), array( + 'loop_nested_deep_multilevel_ref_twig.html', + array(), + array('outer' => array(array()), 'outer.middle' => array(array()), 'outer.middle.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))), + array(), + "top-level content\nouter\nmiddle\ninner z\nfirst row of 2 in inner\n\ninner zz", + ), + array( 'loop_size.html', array(), array('test_loop' => array(array()), 'empty_loop' => array()), @@ -318,6 +418,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "nonexistent = 0\n! nonexistent\n\nempty = 0\n! empty\nloop\n\nin loop", ), array( + 'loop_size_twig.html', + array(), + array('test_loop' => array(array()), 'empty_loop' => array()), + array(), + "nonexistent = 0\n! nonexistent\n\nempty = 0\n! empty\nloop\n\nin loop", + ), + array( 'loop_include.html', array(), array('test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1'))), @@ -325,6 +432,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "barbarbar1bar1", ), array( + 'loop_include_twig.html', + array(), + array('test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1'))), + array(), + "barbarbar1bar1", + ), + array( 'loop_nested_include.html', array(), array( @@ -335,6 +449,17 @@ class phpbb_template_template_test extends phpbb_template_template_test_case "[bar|[bar|]][bar1|[bar1|[bar1|works]]]", array(), ), + array( + 'loop_nested_include_twig.html', + array(), + array( + 'test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1')), + 'test_loop.inner' => array(array('myinner' => 'works')), + ), + array(), + "[bar|[bar|]][bar1|[bar1|[bar1|works]]]", + array(), + ), /* Does not pass with the current implementation. array( 'loop_reuse.html', @@ -343,8 +468,15 @@ class phpbb_template_template_test extends phpbb_template_template_test_case array(), // Not entirely sure what should be outputted but the current output of "a" is most certainly wrong "a\nb\nc\nd", + ),*/ + array( + 'loop_reuse_twig.html', + array(), + array('one' => array(array('VAR' => 'a'), array('VAR' => 'b')), 'one.one' => array(array('VAR' => 'c'), array('VAR' => 'd'))), + array(), + // Not entirely sure what should be outputted but the current output of "a" is most certainly wrong + "a\nb\nc\nd", ), - */ array( 'twig.html', array('VARIABLE' => 'FOObar',), @@ -359,6 +491,27 @@ class phpbb_template_template_test extends phpbb_template_template_test_case array(), 'inner_value', ), + array( + 'loop_expressions.html', + array(), + array('loop' => array(array(),array(),array(),array(),array(),array()),), + array(), + 'yesnononoyesnoyesnonoyesnono', + ), + array( + 'loop_expressions_twig.html', + array(), + array('loop' => array(array(),array(),array(),array(),array(),array()),), + array(), + 'yesnononoyesnoyesnonoyesnono', + ), + array( + 'loop_expressions_twig2.html', + array('loop' => array(array(),array(),array(),array(),array(),array()),), + array(), + array(), + 'yesnononoyesnoyesnonoyesnono', + ), ); } diff --git a/tests/template/template_test_case.php b/tests/template/template_test_case.php index 1250397401..3c97d30edc 100644 --- a/tests/template/template_test_case.php +++ b/tests/template/template_test_case.php @@ -15,6 +15,7 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; class phpbb_template_template_test_case extends phpbb_test_case { + protected $lang; protected $template; protected $template_path; protected $user; @@ -24,6 +25,17 @@ class phpbb_template_template_test_case extends phpbb_test_case // Keep the contents of the cache for debugging? const PRESERVE_CACHE = true; + static protected $language_reflection_lang; + + static public function setUpBeforeClass() + { + parent::setUpBeforeClass(); + + $reflection = new ReflectionClass('\phpbb\language\language'); + self::$language_reflection_lang = $reflection->getProperty('lang'); + self::$language_reflection_lang->setAccessible(true); + } + protected function display($handle) { ob_start(); @@ -65,20 +77,46 @@ class phpbb_template_template_test_case extends phpbb_test_case $defaults = $this->config_defaults(); $config = new \phpbb\config\config(array_merge($defaults, $new_config)); - $this->user = new \phpbb\user('\phpbb\datetime'); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $this->lang = $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $this->user = $user; + + $filesystem = new \phpbb\filesystem\filesystem(); $path_helper = new \phpbb\path_helper( new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + $filesystem, $this->getMock('\phpbb\request\request'), $phpbb_root_path, $phpEx ); $this->template_path = $this->test_path . '/templates'; - $this->template = new \phpbb\template\twig\twig($path_helper, $config, $this->user, new \phpbb\template\context()); + + $container = new phpbb_mock_container_builder(); + $cache_path = $phpbb_root_path . 'cache/twig'; + $context = new \phpbb\template\context(); + $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), ''); + $twig = new \phpbb\template\twig\environment( + $config, + $filesystem, + $path_helper, + $container, + $cache_path, + null, + $loader, + array( + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ) + ); + $this->template = new phpbb\template\twig\twig($path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user))); + $container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig)); $this->template->set_custom_style('tests', $this->template_path); } @@ -88,6 +126,10 @@ class phpbb_template_template_test_case extends phpbb_test_case $this->setup_engine(); $this->template->clear_cache(); + + global $phpbb_filesystem; + + $phpbb_filesystem = new \phpbb\filesystem\filesystem(); } protected function tearDown() @@ -121,12 +163,16 @@ class phpbb_template_template_test_case extends phpbb_test_case { foreach ($lang_vars as $name => $value) { - $this->user->lang[$name] = $value; + self::$language_reflection_lang->setValue($this->lang, array_merge( + self::$language_reflection_lang->getValue($this->lang), + array($name => $value) + )); } } $expected = str_replace(array("\n", "\r", "\t"), '', $expected); $output = str_replace(array("\n", "\r", "\t"), '', $this->display('test')); + $this->assertEquals($expected, $output, "Testing $file"); } } diff --git a/tests/template/template_test_case_with_tree.php b/tests/template/template_test_case_with_tree.php index 68ecc4b706..bf5de6b85e 100644 --- a/tests/template/template_test_case_with_tree.php +++ b/tests/template/template_test_case_with_tree.php @@ -22,11 +22,13 @@ class phpbb_template_template_test_case_with_tree extends phpbb_template_templat $defaults = $this->config_defaults(); $config = new \phpbb\config\config(array_merge($defaults, $new_config)); + $filesystem = new \phpbb\filesystem\filesystem(); + $this->phpbb_path_helper = new \phpbb\path_helper( new \phpbb\symfony_request( new phpbb_mock_request() ), - new \phpbb\filesystem(), + $filesystem, $this->getMock('\phpbb\request\request'), $phpbb_root_path, $phpEx @@ -34,7 +36,28 @@ class phpbb_template_template_test_case_with_tree extends phpbb_template_templat $this->template_path = $this->test_path . '/templates'; $this->parent_template_path = $this->test_path . '/parent_templates'; - $this->template = new phpbb\template\twig\twig($this->phpbb_path_helper, $config, $user, new phpbb\template\context()); + + $container = new phpbb_mock_container_builder(); + $cache_path = $phpbb_root_path . 'cache/twig'; + $context = new \phpbb\template\context(); + $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), ''); + $twig = new \phpbb\template\twig\environment( + $config, + $filesystem, + $this->phpbb_path_helper, + $container, + $cache_path, + null, + $loader, + array( + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ) + ); + $this->template = new phpbb\template\twig\twig($this->phpbb_path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user))); + $container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig)); $this->template->set_custom_style('tests', array($this->template_path, $this->parent_template_path)); } } diff --git a/tests/template/templates/loop_advanced_twig.html b/tests/template/templates/loop_advanced_twig.html new file mode 100644 index 0000000000..fd9fcae045 --- /dev/null +++ b/tests/template/templates/loop_advanced_twig.html @@ -0,0 +1,19 @@ +{% for test_loop_inner in test_loop %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(0) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(0,-1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(1,1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(0,1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(2,4) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(0,-7) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(-2,6) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} +x +{% for test_loop_inner in test_loop|subset(-2,-1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %} diff --git a/tests/template/templates/loop_expressions.html b/tests/template/templates/loop_expressions.html index 6bff53f388..ddb9fd52fa 100644 --- a/tests/template/templates/loop_expressions.html +++ b/tests/template/templates/loop_expressions.html @@ -1,11 +1,11 @@ <!-- BEGIN loop --> -<!-- IF loop.S_ROW_NUM is even by 4 -->on<!-- ELSE -->off<!-- ENDIF --> +<!-- IF loop.S_ROW_NUM is divisible by(4) -->yes<!-- ELSE -->no<!-- ENDIF --> <!-- END loop --> <!-- BEGIN loop --> -<!-- IF loop.S_ROW_NUM is odd by 3 -->on<!-- ELSE -->off<!-- ENDIF --> +<!-- IF loop.S_ROW_NUM is divisible by(3) -->yes<!-- ELSE -->no<!-- ENDIF --> <!-- END loop --> diff --git a/tests/template/templates/loop_expressions_twig.html b/tests/template/templates/loop_expressions_twig.html new file mode 100644 index 0000000000..5ca8cc3601 --- /dev/null +++ b/tests/template/templates/loop_expressions_twig.html @@ -0,0 +1,11 @@ +{% for loop_inner in loop %} + +{% if loop_inner.S_ROW_NUM is divisible by(4) %}yes{% else %}no{% endif %} + +{% endfor %} + +{% for loop_inner in loop %} + +{% if loop_inner.S_ROW_NUM is divisible by(3) %}yes{% else %}no{% endif %} + +{% endfor %} diff --git a/tests/template/templates/loop_expressions_twig2.html b/tests/template/templates/loop_expressions_twig2.html new file mode 100644 index 0000000000..16159ead4c --- /dev/null +++ b/tests/template/templates/loop_expressions_twig2.html @@ -0,0 +1,11 @@ +{% for loop_inner in loop %} + +{% if loop.index0 is divisible by(4) %}yes{% else %}no{% endif %} + +{% endfor %} + +{% for loop_inner in loop %} + +{% if loop.index0 is divisible by(3) %}yes{% else %}no{% endif %} + +{% endfor %} diff --git a/tests/template/templates/loop_include1_twig.html b/tests/template/templates/loop_include1_twig.html new file mode 100644 index 0000000000..2ff9f61b02 --- /dev/null +++ b/tests/template/templates/loop_include1_twig.html @@ -0,0 +1 @@ +{{ test_loop_inner.foo }} diff --git a/tests/template/templates/loop_include_twig.html b/tests/template/templates/loop_include_twig.html new file mode 100644 index 0000000000..1a534e2dbc --- /dev/null +++ b/tests/template/templates/loop_include_twig.html @@ -0,0 +1,4 @@ +{% for test_loop_inner in test_loop %} + {{ test_loop_inner.foo }} + {% INCLUDE 'loop_include1_twig.html' %} +{% endfor %} diff --git a/tests/template/templates/loop_nested2_twig.html b/tests/template/templates/loop_nested2_twig.html new file mode 100644 index 0000000000..cf802dc69f --- /dev/null +++ b/tests/template/templates/loop_nested2_twig.html @@ -0,0 +1,6 @@ +{% for outer_inner in outer %} + o{{ outer_inner.S_ROW_COUNT }} + {% for middle in outer_inner.middle %} + m{{ middle.S_ROW_COUNT }}{{ outer_inner.S_ROW_COUNT }} + {% endfor %} +{% endfor %} diff --git a/tests/template/templates/loop_nested_deep_multilevel_ref_twig.html b/tests/template/templates/loop_nested_deep_multilevel_ref_twig.html new file mode 100644 index 0000000000..9bc68e6e2e --- /dev/null +++ b/tests/template/templates/loop_nested_deep_multilevel_ref_twig.html @@ -0,0 +1,13 @@ +top-level content +{% for outer_inner in outer %} + outer + {% for middle in outer_inner.middle %} + {{ middle.S_BLOCK_NAME }} + {% for inner in middle.inner %} + inner {{ inner.VARIABLE }} + {% if inner.S_FIRST_ROW %} + first row of {{ inner.S_NUM_ROWS }} in {{ inner.S_BLOCK_NAME }} + {% endif %} + {% endfor %} + {% endfor %} +{% endfor %} diff --git a/tests/template/templates/loop_nested_include1_twig.html b/tests/template/templates/loop_nested_include1_twig.html new file mode 100644 index 0000000000..4c2ebb5f15 --- /dev/null +++ b/tests/template/templates/loop_nested_include1_twig.html @@ -0,0 +1,5 @@ +[{{ test_loop_inner.foo }}| +{% for inner in test_loop_inner.inner %} + [{{ test_loop_inner.foo }}| + {{ inner.myinner }}] +{% endfor %}] diff --git a/tests/template/templates/loop_nested_include_twig.html b/tests/template/templates/loop_nested_include_twig.html new file mode 100644 index 0000000000..c92ac922d1 --- /dev/null +++ b/tests/template/templates/loop_nested_include_twig.html @@ -0,0 +1,4 @@ +{% for test_loop_inner in test_loop %} + [{{ test_loop_inner.foo }} + |{% INCLUDE 'loop_nested_include1_twig.html' %}] +{% endfor %} diff --git a/tests/template/templates/loop_nested_multilevel_ref_twig.html b/tests/template/templates/loop_nested_multilevel_ref_twig.html new file mode 100644 index 0000000000..336a57d0bc --- /dev/null +++ b/tests/template/templates/loop_nested_multilevel_ref_twig.html @@ -0,0 +1,10 @@ +top-level content +{% for outer_inner in outer %} + outer {{ outer_inner.VARIABLE }} + {% for inner in outer_inner.inner %} + inner {{ inner.VARIABLE }} + {% if inner.S_FIRST_ROW %} + first row + {% endif %} + {% endfor %} +{% endfor %} diff --git a/tests/template/templates/loop_nested_twig.html b/tests/template/templates/loop_nested_twig.html new file mode 100644 index 0000000000..b294226b3a --- /dev/null +++ b/tests/template/templates/loop_nested_twig.html @@ -0,0 +1,6 @@ +{% for outer_inner in outer %} +outer - {{ outer_inner.S_ROW_COUNT }}{% if outer_inner.VARIABLE %} - {{ outer_inner.VARIABLE }}{% endif %}{% if TEST_MORE %}[{{ outer_inner.S_BLOCK_NAME }}|{{ outer_inner.S_NUM_ROWS }}]{% endif %} +{% for middle in outer_inner.middle %} +middle - {{ middle.S_ROW_COUNT }}{% if middle.VARIABLE %} - {{ middle.VARIABLE }}{% endif %}{% if TEST_MORE %}[{{ middle.S_BLOCK_NAME }}|{{ middle.S_NUM_ROWS }}]{% endif %} +{% endfor %} +{% endfor %} diff --git a/tests/template/templates/loop_reuse_twig.html b/tests/template/templates/loop_reuse_twig.html new file mode 100644 index 0000000000..67452a737f --- /dev/null +++ b/tests/template/templates/loop_reuse_twig.html @@ -0,0 +1,6 @@ +{% for one_inner in one %} + {{ one_inner.VAR }} + {% for one_one_inner in one_inner.one %} + {{ one_one_inner.VAR }} + {% endfor %} +{% endfor %} diff --git a/tests/template/templates/loop_size_twig.html b/tests/template/templates/loop_size_twig.html new file mode 100644 index 0000000000..f6d2571e11 --- /dev/null +++ b/tests/template/templates/loop_size_twig.html @@ -0,0 +1,39 @@ +{% if nonexistent_loop|length %} +nonexistent +{% endif %} + +{% if nonexistent_loop|length == 0 %} +nonexistent = 0 +{% endif %} + +{% if ! nonexistent_loop|length %} +! nonexistent +{% endif %} + +{% if empty_loop|length %} +empty +{% endif %} + +{% if empty_loop|length == 0 %} +empty = 0 +{% endif %} + +{% if ! empty_loop|length %} +! empty +{% endif %} + +{% if test_loop|length %} +loop +{% endif %} + +{% if test_loop|length == 0 %} +loop = 0 +{% endif %} + +{% if ! test_loop|length %} +! loop +{% endif %} + +{% for test_loop_inner in test_loop %} +in loop +{% endfor %} diff --git a/tests/template/templates/loop_twig.html b/tests/template/templates/loop_twig.html new file mode 100644 index 0000000000..fb24f331b3 --- /dev/null +++ b/tests/template/templates/loop_twig.html @@ -0,0 +1,21 @@ +{% for test_loop_inner in test_loop %} +loop +{% else %} +noloop +{% endfor %} + +{% if test_loop|length %} +loop +{% else %} +noloop +{% endif %} + +{% if test_loop|length == 2 %} +loop +{% endif %} + +{% for test_loop_inner in test_loop %} +{% for block_inner in block %} +loop#{{ test_loop_inner.S_ROW_COUNT }}-block#{{ block_inner.S_ROW_COUNT }} +{% endfor %} +{% endfor %} diff --git a/tests/template/templates/loop_underscore_twig.html b/tests/template/templates/loop_underscore_twig.html new file mode 100644 index 0000000000..44b095c882 --- /dev/null +++ b/tests/template/templates/loop_underscore_twig.html @@ -0,0 +1,21 @@ +{% for _underscore_loop_inner in _underscore_loop %} +loop +{% else %} +noloop +{% endfor %} + +{% if _underscore_loop|length %} +loop +{% else %} +noloop +{% endif %} + +{% if _underscore_loop|length == 2 %} +loop +{% endif %} + +{% for _underscore_loop_inner in _underscore_loop %} +{% for block_inner in block %} +loop#{{ loop.S_ROW_COUNT }}-block#{{ block_inner.S_ROW_COUNT }} +{% endfor %} +{% endfor %} diff --git a/tests/template/templates/loop_vars_twig.html b/tests/template/templates/loop_vars_twig.html new file mode 100644 index 0000000000..af6c63d8e3 --- /dev/null +++ b/tests/template/templates/loop_vars_twig.html @@ -0,0 +1,13 @@ +{% for test_loop_inner in test_loop %} +{% if test_loop_inner.S_FIRST_ROW %}first{% endif %} +{{ test_loop_inner.S_ROW_NUM }} - a +{{ test_loop_inner.VARIABLE }} - b +{% if test_loop_inner.VARIABLE %}set{% endif %} +{% if test_loop_inner.S_LAST_ROW %} +last +{% endif %} +{% for inner_inner in test_loop_inner.inner %} +{{ inner_inner.S_ROW_NUM }} - c +{% if inner_inner.S_LAST_ROW and inner_inner.S_ROW_COUNT and inner_inner.S_NUM_ROWS %}last inner{% endif %} +{% endfor %} +{% endfor %} diff --git a/tests/test_framework/mock/phpbb_mock_null_installer_task.php b/tests/test_framework/mock/phpbb_mock_null_installer_task.php new file mode 100644 index 0000000000..c1b880d967 --- /dev/null +++ b/tests/test_framework/mock/phpbb_mock_null_installer_task.php @@ -0,0 +1,30 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +class phpbb_mock_null_installer_task extends \phpbb\install\task_base +{ + public function run() + { + + } + + static public function get_step_count() + { + return 0; + } + + public function get_task_lang_name() + { + return ''; + } +} diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index fc1a3632f4..4d0460ebeb 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -58,7 +58,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test $setup_extensions = static::setup_extensions(); - $finder = new \phpbb\finder(new \phpbb\filesystem(), $phpbb_root_path, null, $phpEx); + $finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), $phpbb_root_path, null, $phpEx); $finder->core_path('phpbb/db/migration/data/'); if (!empty($setup_extensions)) { @@ -77,7 +77,10 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test global $table_prefix; $db = new \phpbb\db\driver\sqlite(); - $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, new \phpbb\db\tools($db, true), $phpbb_root_path, $phpEx, $table_prefix); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($db, true); + + $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, $db_tools, $phpbb_root_path, $phpEx, $table_prefix); file_put_contents(self::$schema_file, json_encode($schema_generator->get_schema())); } diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index 3b5bab749e..27ac64e21d 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -11,7 +11,6 @@ * */ -require_once dirname(__FILE__) . '/../../phpBB/includes/functions_install.php'; require_once dirname(__FILE__) . '/phpbb_database_connection_odbc_pdo_wrapper.php'; class phpbb_database_test_connection_manager @@ -351,10 +350,13 @@ class phpbb_database_test_connection_manager if (file_exists($filename)) { + global $phpbb_root_path; + $queries = file_get_contents($filename); - $sql = phpbb_remove_comments($queries); - $sql = split_sql_file($sql, $this->dbms['DELIM']); + $db_helper = new \phpbb\install\helper\database(new \phpbb\filesystem\filesystem(), $phpbb_root_path); + $sql = $db_helper->remove_comments($queries); + $sql = $db_helper->split_sql_file($sql, $this->dbms['DELIM']); foreach ($sql as $query) { @@ -372,16 +374,20 @@ class phpbb_database_test_connection_manager { global $phpbb_root_path, $phpEx, $table_prefix; - $finder = new \phpbb\finder(new \phpbb\filesystem(), $phpbb_root_path, null, $phpEx); + $finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), $phpbb_root_path, null, $phpEx); $classes = $finder->core_path('phpbb/db/migration/data/') ->get_classes(); $db = new \phpbb\db\driver\sqlite(); - $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, new \phpbb\db\tools($db, true), $phpbb_root_path, $phpEx, $table_prefix); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($db, true); + + $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, $db_tools, $phpbb_root_path, $phpEx, $table_prefix); $db_table_schema = $schema_generator->get_schema(); } - $db_tools = new \phpbb\db\tools($db, true); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($db, true); foreach ($db_table_schema as $table_name => $table_data) { $queries = $db_tools->sql_create_table( diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 8107e45dc7..53519617b3 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -12,13 +12,15 @@ */ use Symfony\Component\BrowserKit\CookieJar; -require_once __DIR__ . '/../../phpBB/includes/functions_install.php'; +require_once __DIR__ . '/mock/phpbb_mock_null_installer_task.php'; class phpbb_functional_test_case extends phpbb_test_case { + /** @var \Goutte\Client */ static protected $client; static protected $cookieJar; static protected $root_url; + static protected $install_success = false; protected $cache = null; protected $db = null; @@ -77,13 +79,15 @@ class phpbb_functional_test_case extends phpbb_test_case { parent::setUp(); + if (!self::$install_success) + { + $this->fail('Installing phpBB has failed.'); + } + $this->bootstrap(); self::$cookieJar = new CookieJar; self::$client = new Goutte\Client(array(), null, self::$cookieJar); - // Reset the curl handle because it is 0 at this point and not a valid - // resource - self::$client->getClient()->getCurlMulti()->reset(true); // Clear the language array so that things // that were added in other tests are gone @@ -169,7 +173,7 @@ class phpbb_functional_test_case extends phpbb_test_case */ static public function get_content() { - return self::$client->getResponse()->getContent(); + return (string) self::$client->getResponse()->getContent(); } // bootstrap, called after board is set up @@ -205,6 +209,11 @@ class phpbb_functional_test_case extends phpbb_test_case { if (!$this->cache) { + global $phpbb_container; + + $phpbb_container = new phpbb_mock_container_builder(); + $phpbb_container->setParameter('core.environment', PHPBB_ENVIRONMENT); + $this->cache = new \phpbb\cache\driver\file; } @@ -226,7 +235,8 @@ class phpbb_functional_test_case extends phpbb_test_case $config = new \phpbb\config\config(array()); $db = $this->get_db(); - $db_tools = new \phpbb\db\tools($db); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($db); $container = new phpbb_mock_container_builder(); $migrator = new \phpbb\db\migrator( @@ -243,14 +253,12 @@ class phpbb_functional_test_case extends phpbb_test_case ); $container->set('migrator', $migrator); $container->set('dispatcher', new phpbb_mock_event_dispatcher()); - $user = new \phpbb\user('\phpbb\datetime'); $extension_manager = new \phpbb\extension\manager( $container, $db, $config, - new phpbb\filesystem(), - $user, + new phpbb\filesystem\filesystem(), self::$config['table_prefix'] . 'ext', dirname(__FILE__) . '/', $phpEx, @@ -282,120 +290,102 @@ class phpbb_functional_test_case extends phpbb_test_case } } - self::$cookieJar = new CookieJar; - self::$client = new Goutte\Client(array(), null, self::$cookieJar); - // Set client manually so we can increase the cURL timeout - self::$client->setClient(new Guzzle\Http\Client('', array( - Guzzle\Http\Client::DISABLE_REDIRECTS => true, - 'curl.options' => array( - CURLOPT_TIMEOUT => 120, - ), - ))); - - // Reset the curl handle because it is 0 at this point and not a valid - // resource - self::$client->getClient()->getCurlMulti()->reset(true); + $container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx); + $container = $container_builder + ->with_environment('installer') + ->without_extensions() + ->without_cache() + ->with_custom_parameters([ + 'core.disable_super_globals' => false, + 'installer.create_config_file.options' => [ + 'debug' => true, + 'environment' => 'test', + ], + 'cache.driver.class' => 'phpbb\cache\driver\file' + ]) + ->without_compiled_container() + ->get_container(); + + $container->register('installer.install_finish.notify_user')->setSynthetic(true); + $container->set('installer.install_finish.notify_user', new phpbb_mock_null_installer_task()); + $container->compile(); + + $language = $container->get('language'); + $language->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting')); + + $iohandler_factory = $container->get('installer.helper.iohandler_factory'); + $iohandler_factory->set_environment('cli'); + $iohandler = $iohandler_factory->get(); $parseURL = parse_url(self::$config['phpbb_functional_url']); - $crawler = self::request('GET', 'install/index.php?mode=install&language=en'); - self::assertContains('Welcome to Installation', $crawler->filter('#main')->text()); - $form = $crawler->selectButton('submit')->form(); - - // install/index.php?mode=install&sub=requirements - $crawler = self::submit($form); - self::assertContains('Installation compatibility', $crawler->filter('#main')->text()); - $form = $crawler->selectButton('submit')->form(); - - // install/index.php?mode=install&sub=database - $crawler = self::submit($form); - self::assertContains('Database configuration', $crawler->filter('#main')->text()); - $form = $crawler->selectButton('submit')->form(array( - // Installer uses 3.0-style dbms name - 'dbms' => str_replace('phpbb\db\driver\\', '', self::$config['dbms']), - 'dbhost' => self::$config['dbhost'], - 'dbport' => self::$config['dbport'], - 'dbname' => self::$config['dbname'], - 'dbuser' => self::$config['dbuser'], - 'dbpasswd' => self::$config['dbpasswd'], - 'table_prefix' => self::$config['table_prefix'], - )); + $output = new \Symfony\Component\Console\Output\NullOutput(); + $style = new \Symfony\Component\Console\Style\SymfonyStyle( + new \Symfony\Component\Console\Input\ArrayInput(array()), + $output + ); + $iohandler->set_style($style, $output); + + $installer = $container->get('installer.installer.install'); + $installer->set_iohandler($iohandler); + + // Set data + $iohandler->set_input('admin_name', 'admin'); + $iohandler->set_input('admin_pass1', 'adminadmin'); + $iohandler->set_input('admin_pass2', 'adminadmin'); + $iohandler->set_input('board_email', 'nobody@example.com'); + $iohandler->set_input('submit_admin', 'submit'); + + $iohandler->set_input('default_lang', 'en'); + $iohandler->set_input('board_name', 'yourdomain.com'); + $iohandler->set_input('board_description', 'A short text to describe your forum'); + $iohandler->set_input('submit_board', 'submit'); + + $iohandler->set_input('dbms', str_replace('phpbb\db\driver\\', '', self::$config['dbms'])); + $iohandler->set_input('dbhost', self::$config['dbhost']); + $iohandler->set_input('dbport', self::$config['dbport']); + $iohandler->set_input('dbuser', self::$config['dbuser']); + $iohandler->set_input('dbpasswd', self::$config['dbpasswd']); + $iohandler->set_input('dbname', self::$config['dbname']); + $iohandler->set_input('table_prefix', self::$config['table_prefix']); + $iohandler->set_input('submit_database', 'submit'); + + $iohandler->set_input('email_enable', true); + $iohandler->set_input('smtp_delivery', '1'); + $iohandler->set_input('smtp_host', 'nxdomain.phpbb.com'); + $iohandler->set_input('smtp_auth', 'PLAIN'); + $iohandler->set_input('smtp_user', 'nxuser'); + $iohandler->set_input('smtp_pass', 'nxpass'); + $iohandler->set_input('submit_email', 'submit'); + + $iohandler->set_input('cookie_secure', '0'); + $iohandler->set_input('server_protocol', '0'); + $iohandler->set_input('force_server_vars', $parseURL['scheme'] . '://'); + $iohandler->set_input('server_name', $parseURL['host']); + $iohandler->set_input('server_port', isset($parseURL['port']) ? (int) $parseURL['port'] : 80); + $iohandler->set_input('script_path', $parseURL['path']); + $iohandler->set_input('submit_server', 'submit'); + + $installer->run(); - // install/index.php?mode=install&sub=database - $crawler = self::submit($form); - self::assertContains('Successful connection', $crawler->filter('#main')->text()); - $form = $crawler->selectButton('submit')->form(); + copy($config_file, $config_file_test); - // install/index.php?mode=install&sub=administrator - $crawler = self::submit($form); - self::assertContains('Administrator configuration', $crawler->filter('#main')->text()); - $form = $crawler->selectButton('submit')->form(array( - 'default_lang' => 'en', - 'admin_name' => 'admin', - 'admin_pass1' => 'adminadmin', - 'admin_pass2' => 'adminadmin', - 'board_email' => 'nobody@example.com', - )); + self::$install_success = true; - // install/index.php?mode=install&sub=administrator - $crawler = self::submit($form); - self::assertContains('Tests passed', $crawler->filter('#main')->text()); - $form = $crawler->selectButton('submit')->form(); - - // We have to skip install/index.php?mode=install&sub=config_file - // because that step will create a config.php file if phpBB has the - // permission to do so. We have to create the config file on our own - // in order to get the DEBUG constants defined. - $config_php_data = phpbb_create_config_file_data(self::$config, self::$config['dbms'], true, false, true); - $config_created = file_put_contents($config_file, $config_php_data) !== false; - if (!$config_created) + if (file_exists($phpbb_root_path . 'store/install_config.php')) { - self::markTestSkipped("Could not write $config_file file."); + self::$install_success = false; + @unlink($phpbb_root_path . 'store/install_config.php'); } - // We also have to create a install lock that is normally created by - // the installer. The file will be removed by the final step of the - // installer. - $install_lock_file = $phpbb_root_path . 'cache/install_lock'; - $lock_created = file_put_contents($install_lock_file, '') !== false; - if (!$lock_created) + if (file_exists($phpbb_root_path . 'cache/install_lock')) { - self::markTestSkipped("Could not create $lock_created file."); + @unlink($phpbb_root_path . 'cache/install_lock'); } - @chmod($install_lock_file, 0666); - - // install/index.php?mode=install&sub=advanced - $form_data = $form->getValues(); - unset($form_data['submit']); - - $crawler = self::request('POST', 'install/index.php?mode=install&sub=advanced', $form_data); - self::assertContains('The settings on this page are only necessary to set if you know that you require something different from the default.', $crawler->filter('#main')->text()); - $form = $crawler->selectButton('submit')->form(array( - 'email_enable' => true, - 'smtp_delivery' => true, - 'smtp_host' => 'nxdomain.phpbb.com', - 'smtp_auth' => 'PLAIN', - 'smtp_user' => 'nxuser', - 'smtp_pass' => 'nxpass', - 'cookie_secure' => false, - 'force_server_vars' => false, - 'server_protocol' => $parseURL['scheme'] . '://', - 'server_name' => 'localhost', - 'server_port' => isset($parseURL['port']) ? (int) $parseURL['port'] : 80, - 'script_path' => $parseURL['path'], - )); - - // install/index.php?mode=install&sub=create_table - $crawler = self::submit($form); - self::assertContains('The database tables used by phpBB', $crawler->filter('#main')->text()); - self::assertContains('have been created and populated with some initial data.', $crawler->filter('#main')->text()); - $form = $crawler->selectButton('submit')->form(); - // install/index.php?mode=install&sub=final - $crawler = self::submit($form); - self::assertContains('You have successfully installed', $crawler->text()); - - copy($config_file, $config_file_test); + global $phpbb_container, $cache, $phpbb_dispatcher, $request, $user, $auth, $db, $config, $phpbb_log, $symfony_request, $phpbb_filesystem, $phpbb_path_helper, $phpbb_extension_manager, $template; + $phpbb_container->reset(); + unset($phpbb_container, $cache, $phpbb_dispatcher, $request, $user, $auth, $db, $config, $phpbb_log, $symfony_request, $phpbb_filesystem, $phpbb_path_helper, $phpbb_extension_manager, $template); } public function install_ext($extension) @@ -490,7 +480,7 @@ class phpbb_functional_test_case extends phpbb_test_case )); $db->sql_query($sql); - if ($style_path != 'prosilver' && $style_path != 'subsilver2') + if ($style_path != 'prosilver') { @mkdir($phpbb_root_path . 'styles/' . $style_path, 0777); @mkdir($phpbb_root_path . 'styles/' . $style_path . '/template', 0777); @@ -529,7 +519,7 @@ class phpbb_functional_test_case extends phpbb_test_case $db->sql_query('DELETE FROM ' . STYLES_TEMPLATE_TABLE . ' WHERE template_id = ' . $style_id); $db->sql_query('DELETE FROM ' . STYLES_THEME_TABLE . ' WHERE theme_id = ' . $style_id); - if ($style_path != 'prosilver' && $style_path != 'subsilver2') + if ($style_path != 'prosilver') { @rmdir($phpbb_root_path . 'styles/' . $style_path . '/template'); @rmdir($phpbb_root_path . 'styles/' . $style_path); @@ -571,7 +561,7 @@ class phpbb_functional_test_case extends phpbb_test_case } $cache = new phpbb_mock_null_cache; - $cache_driver = new \phpbb\cache\driver\null(); + $cache_driver = new \phpbb\cache\driver\dummy(); $phpbb_container = new phpbb_mock_container_builder(); $phpbb_container->set('cache.driver', $cache_driver); $phpbb_notifications = new phpbb_mock_notification_manager(); @@ -585,8 +575,7 @@ class phpbb_functional_test_case extends phpbb_test_case { require_once(__DIR__ . '/../../phpBB/includes/functions_user.php'); } - set_config(null, null, null, $config); - set_config_count(null, null, null, $config); + $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); $passwords_manager = $this->get_passwords_manager(); @@ -612,13 +601,16 @@ class phpbb_functional_test_case extends phpbb_test_case $db = $this->get_db(); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $auth = $this->getMock('\phpbb\auth\auth'); $phpbb_log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE); $cache = new phpbb_mock_null_cache; - $cache_driver = new \phpbb\cache\driver\null(); + $cache_driver = new \phpbb\cache\driver\dummy(); $phpbb_container = new phpbb_mock_container_builder(); $phpbb_container->set('cache.driver', $cache_driver); $phpbb_container->set('notification_manager', new phpbb_mock_notification_manager()); @@ -651,13 +643,16 @@ class phpbb_functional_test_case extends phpbb_test_case $db = $this->get_db(); $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); - $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime')); + $user = $this->getMock('\phpbb\user', array(), array( + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime' + )); $auth = $this->getMock('\phpbb\auth\auth'); $phpbb_log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE); $cache = new phpbb_mock_null_cache; - $cache_driver = new \phpbb\cache\driver\null(); + $cache_driver = new \phpbb\cache\driver\dummy(); $phpbb_container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); $phpbb_container ->expects($this->any()) @@ -856,7 +851,7 @@ class phpbb_functional_test_case extends phpbb_test_case static public function assert_response_html($status_code = 200) { // Any output before the doc type means there was an error - $content = self::$client->getResponse()->getContent(); + $content = self::get_content(); self::assertNotContains('[phpBB Debug]', $content); self::assertStringStartsWith('<!DOCTYPE', trim($content), 'Output found before DOCTYPE specification.'); @@ -877,7 +872,7 @@ class phpbb_functional_test_case extends phpbb_test_case static public function assert_response_xml($status_code = 200) { // Any output before the xml opening means there was an error - $content = self::$client->getResponse()->getContent(); + $content = self::get_content(); self::assertNotContains('[phpBB Debug]', $content); self::assertStringStartsWith('<?xml', trim($content), 'Output found before XML specification.'); @@ -948,8 +943,7 @@ class phpbb_functional_test_case extends phpbb_test_case */ public function assert_checkbox_is_unchecked($crawler, $name, $message = '') { - $this->assertSame( - '', + $this->assertNull( $this->assert_find_one_checkbox($crawler, $name)->attr('checked'), $message ?: "Failed asserting that checkbox $name is unchecked." ); diff --git a/tests/test_framework/phpbb_session_test_case.php b/tests/test_framework/phpbb_session_test_case.php index 1bf0277fe0..1c1930e88d 100644 --- a/tests/test_framework/phpbb_session_test_case.php +++ b/tests/test_framework/phpbb_session_test_case.php @@ -34,7 +34,7 @@ abstract class phpbb_session_test_case extends phpbb_database_test_case $symfony_request = new \phpbb\symfony_request( new phpbb_mock_request() ); - $phpbb_filesystem = new \phpbb\filesystem(); + $phpbb_filesystem = new \phpbb\filesystem\filesystem(); $phpbb_path_helper = new \phpbb\path_helper( $symfony_request, $phpbb_filesystem, diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index dee70ad016..c4b653ec7c 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -11,6 +11,8 @@ * */ +use Symfony\Component\DependencyInjection\ContainerInterface; + class phpbb_test_case_helpers { protected $expectedTriggerError = false; @@ -298,4 +300,295 @@ class phpbb_test_case_helpers } } } + + /** + * Set working instances of the text_formatter.* services + * + * If no container is passed, the global $phpbb_container will be used and/or + * created if applicable + * + * @param ContainerInterface $container Service container + * @param string $fixture Path to the XML fixture + * @param string $styles_path Path to the styles dir + * @return ContainerInterface + */ + public function set_s9e_services(ContainerInterface $container = null, $fixture = null, $styles_path = null) + { + static $first_run; + global $config, $phpbb_container, $phpbb_dispatcher, $phpbb_root_path, $phpEx, $request, $user; + + $cache_dir = __DIR__ . '/../tmp/'; + + // Remove old cache files on first run + if (!isset($first_run)) + { + $first_run = 1; + + array_map('unlink', array_merge( + glob($cache_dir . 'data_s9e_*'), + glob($cache_dir . 's9e_*') + )); + } + + if (!isset($container)) + { + if (!isset($phpbb_container)) + { + $phpbb_container = new phpbb_mock_container_builder; + } + + $container = $phpbb_container; + } + + if (!isset($fixture)) + { + $fixture = __DIR__ . '/../text_formatter/s9e/fixtures/default_formatting.xml'; + } + + if (!isset($styles_path)) + { + $styles_path = $phpbb_root_path . 'styles/'; + } + + $dataset = new DOMDocument; + $dataset->load($fixture); + + $tables = array( + 'phpbb_bbcodes' => array(), + 'phpbb_smilies' => array(), + 'phpbb_styles' => array(), + 'phpbb_words' => array() + ); + foreach ($dataset->getElementsByTagName('table') as $table) + { + $name = $table->getAttribute('name'); + $columns = array(); + + foreach ($table->getElementsByTagName('column') as $column) + { + $columns[] = $column->textContent; + } + + foreach ($table->getElementsByTagName('row') as $row) + { + $values = array(); + + foreach ($row->getElementsByTagName('value') as $value) + { + $values[] = $value->textContent; + } + + $tables[$name][] = array_combine($columns, $values); + } + } + + // Set up a default style if there's none set + if (empty($tables['phpbb_styles'])) + { + $tables['phpbb_styles'][] = array( + 'style_id' => 1, + 'style_path' => 'prosilver', + 'bbcode_bitfield' => 'kNg=' + ); + } + + // Mock the DAL, make it return data from the fixture + $mb = $this->test_case->getMockBuilder('phpbb\\textformatter\\data_access'); + $mb->setMethods(array('get_bbcodes', 'get_censored_words', 'get_smilies', 'get_styles')); + $mb->setConstructorArgs(array( + $this->test_case->getMock('phpbb\\db\\driver\\driver'), + 'phpbb_bbcodes', + 'phpbb_smilies', + 'phpbb_styles', + 'phpbb_words', + $styles_path + )); + + $dal = $mb->getMock(); + $container->set('text_formatter.data_access', $dal); + + $dal->expects($this->test_case->any()) + ->method('get_bbcodes') + ->will($this->test_case->returnValue($tables['phpbb_bbcodes'])); + $dal->expects($this->test_case->any()) + ->method('get_smilies') + ->will($this->test_case->returnValue($tables['phpbb_smilies'])); + $dal->expects($this->test_case->any()) + ->method('get_styles') + ->will($this->test_case->returnValue($tables['phpbb_styles'])); + $dal->expects($this->test_case->any()) + ->method('get_censored_words') + ->will($this->test_case->returnValue($tables['phpbb_words'])); + + // Cache the parser and renderer with a key based on this method's arguments + $cache = new \phpbb\cache\driver\file($cache_dir); + $prefix = '_s9e_' . md5(serialize(func_get_args())); + $cache_key_parser = $prefix . '_parser'; + $cache_key_renderer = $prefix . '_renderer'; + $container->set('cache.driver', $cache); + + if (!$container->isFrozen()) + { + $container->setParameter('cache.dir', $cache_dir); + } + + // Create a path_helper + if (!$container->has('path_helper') || $container->getDefinition('path_helper')->isSynthetic()) + { + $path_helper = $this->test_case->getMockBuilder('phpbb\\path_helper') + ->disableOriginalConstructor() + ->setMethods(array('get_web_root_path')) + ->getMock(); + $path_helper->expects($this->test_case->any()) + ->method('get_web_root_path') + ->will($this->test_case->returnValue('phpBB/')); + + $container->set('path_helper', $path_helper); + } + else + { + $path_helper = $container->get('path_helper'); + } + + // Create an event dispatcher + if ($container->has('dispatcher')) + { + $dispatcher = $container->get('dispatcher'); + } + else if (isset($phpbb_dispatcher)) + { + $dispatcher = $phpbb_dispatcher; + } + else + { + $dispatcher = new phpbb_mock_event_dispatcher; + } + if (!isset($phpbb_dispatcher)) + { + $phpbb_dispatcher = $dispatcher; + } + + // Set up the a minimum config + if ($container->has('config')) + { + $config = $container->get('config'); + } + elseif (!isset($config)) + { + $config = new \phpbb\config\config(array()); + } + $default_config = array( + 'allow_nocensors' => false, + 'allowed_schemes_links' => 'http,https,ftp', + 'script_path' => '/phpbb', + 'server_name' => 'localhost', + 'server_port' => 80, + 'server_protocol' => 'http://', + 'smilies_path' => 'images/smilies', + ); + foreach ($default_config as $config_name => $config_value) + { + if (!isset($config[$config_name])) + { + $config[$config_name] = $config_value; + } + } + + // Create a fake request + if (!isset($request)) + { + $request = new phpbb_mock_request; + } + + // Create and register the text_formatter.s9e.factory service + $factory = new \phpbb\textformatter\s9e\factory($dal, $cache, $dispatcher, $config, new \phpbb\textformatter\s9e\link_helper, $cache_dir, $cache_key_parser, $cache_key_renderer); + $container->set('text_formatter.s9e.factory', $factory); + + // Create a user if none was provided, and add the common lang strings + if ($container->has('user')) + { + $user = $container->get('user'); + } + else + { + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + + $user = $this->test_case->getMockBuilder('\phpbb\user') + ->setConstructorArgs(array($lang, '\phpbb\datetime')) + ->setMethods(array('format_date')) + ->getMock(); + $user->expects($this->test_case->any()) + ->method('format_date') + ->will($this->test_case->returnCallback(__CLASS__ . '::format_date')); + + $user->date_format = 'Y-m-d H:i:s'; + $user->optionset('viewcensors', true); + $user->optionset('viewflash', true); + $user->optionset('viewimg', true); + $user->optionset('viewsmilies', true); + $user->timezone = new \DateTimeZone('UTC'); + $container->set('user', $user); + } + $user->add_lang('common'); + + if (!isset($user->style)) + { + $user->style = array('style_id' => 1); + } + + // Create and register a quote_helper + $quote_helper = new \phpbb\textformatter\s9e\quote_helper( + $container->get('user'), + $phpbb_root_path, + $phpEx + ); + $container->set('text_formatter.s9e.quote_helper', $quote_helper); + + // Create and register the text_formatter.s9e.parser service and its alias + $parser = new \phpbb\textformatter\s9e\parser( + $cache, + $cache_key_parser, + $factory, + $dispatcher + ); + $container->set('text_formatter.parser', $parser); + $container->set('text_formatter.s9e.parser', $parser); + + // Create and register the text_formatter.s9e.renderer service and its alias + $renderer = new \phpbb\textformatter\s9e\renderer( + $cache, + $cache_dir, + $cache_key_renderer, + $factory, + $dispatcher + ); + + // Calls configured in services.yml + $auth = ($container->has('auth')) ? $container->get('auth') : new \phpbb\auth\auth; + $renderer->configure_quote_helper($quote_helper); + $renderer->configure_smilies_path($config, $path_helper); + $renderer->configure_user($user, $config, $auth); + + $container->set('text_formatter.renderer', $renderer); + $container->set('text_formatter.s9e.renderer', $renderer); + + // Create and register the text_formatter.s9e.utils service and its alias + $utils = new \phpbb\textformatter\s9e\utils; + $container->set('text_formatter.utils', $utils); + $container->set('text_formatter.s9e.utils', $utils); + + return $container; + } + + /** + * Mocked replacement for \phpbb\user::format_date() + * + * @param integer $gmepoch unix timestamp + * @return string + */ + static public function format_date($gmepoch) + { + return gmdate('Y-m-d H:i:s', $gmepoch); + } } diff --git a/tests/test_framework/phpbb_ui_test_case.php b/tests/test_framework/phpbb_ui_test_case.php index c8ac492e25..b5ac3a576b 100644 --- a/tests/test_framework/phpbb_ui_test_case.php +++ b/tests/test_framework/phpbb_ui_test_case.php @@ -11,7 +11,12 @@ * */ -require_once __DIR__ . '/../../phpBB/includes/functions_install.php'; +use Facebook\WebDriver\WebDriverBy; +use Facebook\WebDriver\Exception\WebDriverCurlException; +use Facebook\WebDriver\Remote\RemoteWebDriver; +use Facebook\WebDriver\Remote\DesiredCapabilities; + +require_once __DIR__ . '/mock/phpbb_mock_null_installer_task.php'; class phpbb_ui_test_case extends phpbb_test_case { @@ -19,13 +24,27 @@ class phpbb_ui_test_case extends phpbb_test_case static protected $port = 8910; /** - * @var \RemoteWebDriver + * @var RemoteWebDriver */ static protected $webDriver; static protected $config; static protected $root_url; static protected $already_installed = false; + static protected $install_success = false; + static protected $db; + + /** + * Session ID for current test's session (each test makes its own) + * @var string + */ + protected $sid; + + /** + * Language array used by phpBB + * @var array + */ + protected $lang = array(); static public function setUpBeforeClass() { @@ -35,7 +54,7 @@ class phpbb_ui_test_case extends phpbb_test_case { self::markTestSkipped('UI test case requires at least PHP 5.3.19.'); } - else if (!class_exists('\RemoteWebDriver')) + else if (!class_exists('\Facebook\WebDriver\Remote\RemoteWebDriver')) { self::markTestSkipped( 'Could not find RemoteWebDriver class. ' . @@ -60,7 +79,7 @@ class phpbb_ui_test_case extends phpbb_test_case if (!self::$webDriver) { try { - $capabilities = array(\WebDriverCapabilityType::BROWSER_NAME => 'firefox'); + $capabilities = DesiredCapabilities::firefox(); self::$webDriver = RemoteWebDriver::create(self::$host . ':' . self::$port, $capabilities); } catch (WebDriverCurlException $e) { self::markTestSkipped('PhantomJS webserver is not running.'); @@ -74,6 +93,30 @@ class phpbb_ui_test_case extends phpbb_test_case } } + public function setUp() + { + if (!self::$install_success) + { + $this->fail('Installing phpBB has failed.'); + } + + // Clear the language array so that things + // that were added in other tests are gone + $this->lang = array(); + $this->add_lang('common'); + } + + protected function tearDown() + { + parent::tearDown(); + + if (self::$db instanceof \phpbb\db\driver\driver_interface) + { + // Close the database connections again this test + self::$db->sql_close(); + } + } + static public function visit($path) { self::$webDriver->get(self::$root_url . $path); @@ -98,10 +141,12 @@ class phpbb_ui_test_case extends phpbb_test_case static public function install_board() { - global $phpbb_root_path, $phpEx; + global $phpbb_root_path, $phpEx, $db; self::recreate_database(self::$config); + $db = self::get_db(); + $config_file = $phpbb_root_path . "config.$phpEx"; $config_file_dev = $phpbb_root_path . "config_dev.$phpEx"; $config_file_test = $phpbb_root_path . "config_test.$phpEx"; @@ -118,87 +163,298 @@ class phpbb_ui_test_case extends phpbb_test_case } } + $container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx); + $container = $container_builder + ->with_environment('installer') + ->without_extensions() + ->without_cache() + ->with_custom_parameters([ + 'core.disable_super_globals' => false, + 'installer.create_config_file.options' => [ + 'debug' => true, + 'environment' => 'test', + ], + 'cache.driver.class' => 'phpbb\cache\driver\file' + ]) + ->without_compiled_container() + ->get_container(); + + $container->register('installer.install_finish.notify_user')->setSynthetic(true); + $container->set('installer.install_finish.notify_user', new phpbb_mock_null_installer_task()); + $container->compile(); + + $language = $container->get('language'); + $language->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting')); + + $iohandler_factory = $container->get('installer.helper.iohandler_factory'); + $iohandler_factory->set_environment('cli'); + $iohandler = $iohandler_factory->get(); + $parseURL = parse_url(self::$config['phpbb_functional_url']); - self::visit('install/index.php?mode=install&language=en'); - self::assertContains('Welcome to Installation', self::find_element('id', 'main')->getText()); + $output = new \Symfony\Component\Console\Output\NullOutput(); + $style = new \Symfony\Component\Console\Style\SymfonyStyle( + new \Symfony\Component\Console\Input\ArrayInput(array()), + $output + ); + $iohandler->set_style($style, $output); + + $installer = $container->get('installer.installer.install'); + $installer->set_iohandler($iohandler); + + // Set data + $iohandler->set_input('admin_name', 'admin'); + $iohandler->set_input('admin_pass1', 'adminadmin'); + $iohandler->set_input('admin_pass2', 'adminadmin'); + $iohandler->set_input('board_email', 'nobody@example.com'); + $iohandler->set_input('submit_admin', 'submit'); + + $iohandler->set_input('default_lang', 'en'); + $iohandler->set_input('board_name', 'yourdomain.com'); + $iohandler->set_input('board_description', 'A short text to describe your forum'); + $iohandler->set_input('submit_board', 'submit'); + + $iohandler->set_input('dbms', str_replace('phpbb\db\driver\\', '', self::$config['dbms'])); + $iohandler->set_input('dbhost', self::$config['dbhost']); + $iohandler->set_input('dbport', self::$config['dbport']); + $iohandler->set_input('dbuser', self::$config['dbuser']); + $iohandler->set_input('dbpasswd', self::$config['dbpasswd']); + $iohandler->set_input('dbname', self::$config['dbname']); + $iohandler->set_input('table_prefix', self::$config['table_prefix']); + $iohandler->set_input('submit_database', 'submit'); + + $iohandler->set_input('email_enable', true); + $iohandler->set_input('smtp_delivery', '1'); + $iohandler->set_input('smtp_host', 'nxdomain.phpbb.com'); + $iohandler->set_input('smtp_auth', 'PLAIN'); + $iohandler->set_input('smtp_user', 'nxuser'); + $iohandler->set_input('smtp_pass', 'nxpass'); + $iohandler->set_input('submit_email', 'submit'); + + $iohandler->set_input('cookie_secure', '0'); + $iohandler->set_input('server_protocol', '0'); + $iohandler->set_input('force_server_vars', $parseURL['scheme'] . '://'); + $iohandler->set_input('server_name', $parseURL['host']); + $iohandler->set_input('server_port', isset($parseURL['port']) ? (int) $parseURL['port'] : 80); + $iohandler->set_input('script_path', $parseURL['path']); + $iohandler->set_input('submit_server', 'submit'); + + $installer->run(); + + copy($config_file, $config_file_test); + + self::$install_success = true; + + if (file_exists($phpbb_root_path . 'store/install_config.php')) + { + self::$install_success = false; + @unlink($phpbb_root_path . 'store/install_config.php'); + } + + if (file_exists($phpbb_root_path . 'cache/install_lock')) + { + @unlink($phpbb_root_path . 'cache/install_lock'); + } + + global $phpbb_container, $cache, $phpbb_dispatcher, $request, $user, $auth, $db, $config, $phpbb_log, $symfony_request, $phpbb_filesystem, $phpbb_path_helper, $phpbb_extension_manager, $template; + $phpbb_container->reset(); + unset($phpbb_container, $cache, $phpbb_dispatcher, $request, $user, $auth, $db, $config, $phpbb_log, $symfony_request, $phpbb_filesystem, $phpbb_path_helper, $phpbb_extension_manager, $template); + } + + static protected function get_db() + { + global $phpbb_root_path, $phpEx; + // so we don't reopen an open connection + if (!(self::$db instanceof \phpbb\db\driver\driver_interface)) + { + $dbms = self::$config['dbms']; + /** @var \phpbb\db\driver\driver_interface $db */ + $db = new $dbms(); + $db->sql_connect(self::$config['dbhost'], self::$config['dbuser'], self::$config['dbpasswd'], self::$config['dbname'], self::$config['dbport']); + self::$db = $db; + } + return self::$db; + } + + protected function logout() + { + $this->add_lang('ucp'); + + if (empty($this->sid)) + { + return; + } + + $this->visit('ucp.php?sid=' . $this->sid . '&mode=logout'); + $this->assertContains($this->lang('REGISTER'), self::$webDriver->getPageSource()); + unset($this->sid); + + } + + /** + * Login to the ACP + * You must run login() before calling this. + */ + protected function admin_login($username = 'admin') + { + $this->add_lang('acp/common'); + + // Requires login first! + if (empty($this->sid)) + { + $this->fail('$this->sid is empty. Make sure you call login() before admin_login()'); + return; + } + + self::$webDriver->manage()->deleteAllCookies(); - // install/index.php?mode=install&sub=requirements - self::submit(); - self::assertContains('Installation compatibility', self::find_element('id', 'main')->getText()); + $this->visit('adm/index.php?sid=' . $this->sid); + $this->assertContains($this->lang('LOGIN_ADMIN_CONFIRM'), self::$webDriver->getPageSource()); - // install/index.php?mode=install&sub=database - self::submit(); - self::assertContains('Database configuration', self::find_element('id', 'main')->getText()); + self::find_element('cssSelector', 'input[name=username]')->clear()->sendKeys($username); + self::find_element('cssSelector', 'input[type=password]')->sendKeys($username . $username); + self::find_element('cssSelector', 'input[name=login]')->click(); + $this->assertContains($this->lang('ADMIN_PANEL'), $this->find_element('cssSelector', 'h1')->getText()); - self::find_element('id','dbms')->sendKeys(str_replace('phpbb\db\driver\\', '', self::$config['dbms'])); - self::find_element('id','dbhost')->sendKeys(self::$config['dbhost']); - self::find_element('id','dbport')->sendKeys(self::$config['dbport']); - self::find_element('id','dbname')->sendKeys(self::$config['dbname']); - self::find_element('id','dbuser')->sendKeys(self::$config['dbuser']); - self::find_element('id','dbpasswd')->sendKeys(self::$config['dbpasswd']); + $cookies = self::$webDriver->manage()->getCookies(); - // Need to clear default phpbb_ prefix - self::find_element('id','table_prefix')->clear(); - self::find_element('id','table_prefix')->sendKeys(self::$config['table_prefix']); + // The session id is stored in a cookie that ends with _sid - we assume there is only one such cookie + foreach ($cookies as $cookie) + { + if (substr($cookie['name'], -4) == '_sid') + { + $this->sid = $cookie['value']; - // install/index.php?mode=install&sub=database - self::submit(); - self::assertContains('Successful connection', self::find_element('id','main')->getText()); + break; + } + } - // install/index.php?mode=install&sub=administrator - self::submit(); - self::assertContains('Administrator configuration', self::find_element('id','main')->getText()); + $this->assertNotEmpty($this->sid); + } - self::find_element('id','admin_name')->sendKeys('admin'); - self::find_element('id','admin_pass1')->sendKeys('adminadmin'); - self::find_element('id','admin_pass2')->sendKeys('adminadmin'); - self::find_element('id','board_email')->sendKeys('nobody@example.com'); + protected function add_lang($lang_file) + { + if (is_array($lang_file)) + { + foreach ($lang_file as $file) + { + $this->add_lang($file); + } + } - // install/index.php?mode=install&sub=administrator - self::submit(); - self::assertContains('Tests passed', self::find_element('id','main')->getText()); + $lang_path = __DIR__ . "/../../phpBB/language/en/$lang_file.php"; + + $lang = array(); + + if (file_exists($lang_path)) + { + include($lang_path); + } - // install/index.php?mode=install&sub=config_file - self::submit(); + $this->lang = array_merge($this->lang, $lang); + } - // Installer has created a config.php file, we will overwrite it with a - // config file of our own in order to get the DEBUG constants defined - $config_php_data = phpbb_create_config_file_data(self::$config, self::$config['dbms'], true, false, true); - $config_created = file_put_contents($config_file, $config_php_data) !== false; - if (!$config_created) + protected function add_lang_ext($ext_name, $lang_file) + { + if (is_array($lang_file)) { - self::markTestSkipped("Could not write $config_file file."); + foreach ($lang_file as $file) + { + $this->add_lang_ext($ext_name, $file); + } + + return; } - if (strpos(self::find_element('id','main')->getText(), 'The configuration file has been written') === false) + $lang_path = __DIR__ . "/../../phpBB/ext/{$ext_name}/language/en/$lang_file.php"; + + $lang = array(); + + if (file_exists($lang_path)) { - self::submit('id', 'dldone'); + include($lang_path); } - self::assertContains('The configuration file has been written', self::find_element('id','main')->getText()); - // install/index.php?mode=install&sub=advanced - self::submit(); - self::assertContains('The settings on this page are only necessary to set if you know that you require something different from the default.', self::find_element('id','main')->getText()); + $this->lang = array_merge($this->lang, $lang); + } - self::find_element('id','smtp_delivery')->sendKeys('1'); - self::find_element('id','smtp_host')->sendKeys('nxdomain.phpbb.com'); - self::find_element('id','smtp_user')->sendKeys('nxuser'); - self::find_element('id','smtp_pass')->sendKeys('nxpass'); - self::find_element('id','server_protocol')->sendKeys($parseURL['scheme'] . '://'); - self::find_element('id','server_name')->sendKeys('localhost'); - self::find_element('id','server_port')->sendKeys(isset($parseURL['port']) ? $parseURL['port'] : 80); - self::find_element('id','script_path')->sendKeys($parseURL['path']); + protected function lang() + { + $args = func_get_args(); + $key = $args[0]; - // install/index.php?mode=install&sub=create_table - self::submit(); - self::assertContains('The database tables used by phpBB', self::find_element('id','main')->getText()); - self::assertContains('have been created and populated with some initial data.', self::find_element('id','main')->getText()); + if (empty($this->lang[$key])) + { + throw new RuntimeException('Language key "' . $key . '" could not be found.'); + } - // install/index.php?mode=install&sub=final - self::submit(); - self::assertContains('You have successfully installed', self::find_element('id', 'main')->getText()); + $args[0] = $this->lang[$key]; - copy($config_file, $config_file_test); + return call_user_func_array('sprintf', $args); + } + + /** + * assertContains for language strings + * + * @param string $needle Search string + * @param string $haystack Search this + * @param string $message Optional failure message + */ + public function assertContainsLang($needle, $haystack, $message = null) + { + $this->assertContains(html_entity_decode($this->lang($needle), ENT_QUOTES), $haystack, $message); + } + + /** + * assertNotContains for language strings + * + * @param string $needle Search string + * @param string $haystack Search this + * @param string $message Optional failure message + */ + public function assertNotContainsLang($needle, $haystack, $message = null) + { + $this->assertNotContains(html_entity_decode($this->lang($needle), ENT_QUOTES), $haystack, $message); + } + + protected function login($username = 'admin') + { + $this->add_lang('ucp'); + + $this->visit('ucp.php'); + $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), self::$webDriver->getPageSource()); + + self::$webDriver->manage()->deleteAllCookies(); + + self::find_element('cssSelector', 'input[name=username]')->sendKeys($username); + self::find_element('cssSelector', 'input[name=password]')->sendKeys($username . $username); + self::find_element('cssSelector', 'input[name=login]')->click(); + $this->assertNotContains($this->lang('LOGIN'), $this->find_element('className', 'navbar')->getText()); + + $cookies = self::$webDriver->manage()->getCookies(); + + // The session id is stored in a cookie that ends with _sid - we assume there is only one such cookie + foreach ($cookies as $cookie) + { + if (substr($cookie['name'], -4) == '_sid') + { + $this->sid = $cookie['value']; + } + } + + $this->assertNotEmpty($this->sid); + } + + /** + * Take screenshot. Can be used for debug purposes. + * + * @throws Exception When screenshot can't be created + */ + public function take_screenshot() + { + // Change the Path to your own settings + $screenshot = time() . ".png"; + + self::$webDriver->takeScreenshot($screenshot); } } diff --git a/tests/text_formatter/s9e/default_formatting_test.php b/tests/text_formatter/s9e/default_formatting_test.php new file mode 100644 index 0000000000..1f7df15434 --- /dev/null +++ b/tests/text_formatter/s9e/default_formatting_test.php @@ -0,0 +1,315 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +require_once __DIR__ . '/../../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../../phpBB/includes/functions_content.php'; + +class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case +{ + public function test_bbcode_code_lang_is_saved() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $parser = $container->get('text_formatter.parser'); + + $original = '[code]...[/code][code=php]...[/code]'; + $expected = '<r><CODE><s>[code]</s>...<e>[/code]</e></CODE><CODE lang="php"><s>[code=php]</s>...<e>[/code]</e></CODE></r>'; + + $this->assertXmlStringEqualsXmlString($expected, $parser->parse($original)); + } + + /** + * @dataProvider get_default_formatting_tests + */ + public function test_default_formatting($original, $expected, $setup = null) + { + $fixture = __DIR__ . '/fixtures/default_formatting.xml'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture); + + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + if (isset($setup)) + { + call_user_func($setup, $container); + } + + $parsed_text = $parser->parse($original); + + $this->assertSame($expected, $renderer->render($parsed_text)); + } + + public function get_default_formatting_tests() + { + return array( + array( + '[b]bold[/b]', + '<span style="font-weight: bold">bold</span>' + ), + array( + '[u]underlined[/u]', + '<span style="text-decoration: underline">underlined</span>' + ), + array( + '[i]italic[/i]', + '<span style="font-style: italic">italic</span>' + ), + array( + '[color=#FF0000]colored[/color]', + '<span style="color: #FF0000">colored</span>' + ), + array( + '[color=red]colored[/color]', + '<span style="color: red">colored</span>' + ), + array( + '[size=75]smaller[/size]', + '<span style="font-size: 75%; line-height: normal">smaller</span>' + ), + array( + '[quote]quoted[/quote]', + '<blockquote class="uncited"><div>quoted</div></blockquote>' + ), + array( + '[quote="username"]quoted[/quote]', + '<blockquote><div><cite>username wrote:</cite>quoted</div></blockquote>' + ), + array( + '[code]unparsed code[/code]', + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code</code></pre></div>' + ), + array( + '[list]no item[/list]', + '<ul>no item</ul>' + ), + array( + '[*]unparsed', + '[*]unparsed' + ), + array( + '[list][*]item[/list]', + '<ul><li>item</li></ul>' + ), + array( + '[list][*]item[/*][/list]', + '<ul><li>item</li></ul>' + ), + array( + '[list=1][*]item[/list]', + '<ol style="list-style-type: decimal"><li>item</li></ol>' + ), + array( + '[list=a][*]item[/list]', + '<ol style="list-style-type: lower-alpha"><li>item</li></ol>' + ), + array( + '[list=i][*]item[/list]', + '<ol style="list-style-type: lower-roman"><li>item</li></ol>' + ), + array( + '[list=I][*]item[/list]', + '<ol style="list-style-type: upper-roman"><li>item</li></ol>' + ), + array( + '[list=disc][*]item[/list]', + '<ul style="list-style-type: disc"><li>item</li></ul>' + ), + array( + '[list=circle][*]item[/list]', + '<ul style="list-style-type: circle"><li>item</li></ul>' + ), + array( + '[list=square][*]item[/list]', + '<ul style="list-style-type: square"><li>item</li></ul>' + ), + array( + '[img]https://area51.phpbb.com/images/area51.png[/img]', + '<img src="https://area51.phpbb.com/images/area51.png" class="postimage" alt="Image">' + ), + array( + '[url]https://area51.phpbb.com/[/url]', + '<a href="https://area51.phpbb.com/" class="postlink">https://area51.phpbb.com/</a>' + ), + array( + '[url=https://area51.phpbb.com/]Area51[/url]', + '<a href="https://area51.phpbb.com/" class="postlink">Area51</a>' + ), + array( + '[email]bbcode-test@phpbb.com[/email]', + '<a href="mailto:bbcode-test@phpbb.com">bbcode-test@phpbb.com</a>' + ), + array( + '[email=bbcode-test@phpbb.com]Email[/email]', + '<a href="mailto:bbcode-test@phpbb.com">Email</a>' + ), + array( + '[attachment=0]filename[/attachment]', + '<div class="inline-attachment"><!-- ia0 -->filename<!-- ia0 --></div>' + ), + array( + // PHPBB3-1401 - correct: parsed + '[quote="[test]test"]test [ test[/quote]', + '<blockquote><div><cite>[test]test wrote:</cite>test [ test</div></blockquote>' + ), + array( + // PHPBB3-6117 - correct: parsed + '[quote]test[/quote] test ] and [ test [quote]test[/quote]', + '<blockquote class="uncited"><div>test</div></blockquote> test ] and [ test <blockquote class="uncited"><div>test</div></blockquote>' + ), + array( + // PHPBB3-6200 - correct: parsed + '[quote="["]test[/quote]', + '<blockquote><div><cite>[ wrote:</cite>test</div></blockquote>' + ), + array( + // PHPBB3-9364 - quoted: "test[/[/b]quote] test" / non-quoted: "[/quote] test" - also failed if layout distorted + '[quote]test[/[/b]quote] test [/quote][/quote] test', + '<blockquote class="uncited"><div>test[/[/b]quote] test </div></blockquote>[/quote] test' + ), + array( + // PHPBB3-8096 - first quote tag parsed, second quote tag unparsed + '[quote="a"]a[/quote][quote="a]a[/quote]', + '<blockquote><div><cite>a wrote:</cite>a</div></blockquote>[quote="a]a[/quote]' + ), + array( + // Allow textual bbcodes in textual bbcodes + '[b]bold [i]bold + italic[/i][/b]', + '<span style="font-weight: bold">bold <span style="font-style: italic">bold + italic</span></span>' + ), + array( + // Allow textual bbcodes in url with description + '[url=https://area51.phpbb.com/]Area51 [i]italic[/i][/url]', + '<a href="https://area51.phpbb.com/" class="postlink">Area51 <span style="font-style: italic">italic</span></a>' + ), + array( + // Allow url with description in textual bbcodes + '[i]italic [url=https://area51.phpbb.com/]Area51[/url][/i]', + '<span style="font-style: italic">italic <a href="https://area51.phpbb.com/" class="postlink">Area51</a></span>' + ), + array( + // Do not parse textual bbcodes in code + '[code]unparsed code [b]bold [i]bold + italic[/i][/b][/code]', + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code [b]bold [i]bold + italic[/i][/b]</code></pre></div>' + ), + array( + // Do not parse quote bbcodes in code + '[code]unparsed code [quote="username"]quoted[/quote][/code]', + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code [quote="username"]quoted[/quote]</code></pre></div>' + ), + array( + // Textual bbcode nesting into textual bbcode + '[b]bold [i]bold + italic[/b] italic[/i]', + '<span style="font-weight: bold">bold <span style="font-style: italic">bold + italic</span></span><span style="font-style: italic"> italic</span>' + ), + array( + "[code]\tline1\n line2[/code]", + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>' . "\tline1\n line2</code></pre></div>" + ), + array( + "[code]\n\tline1\n line2[/code]", + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>' . "\tline1\n line2</code></pre></div>" + ), + array( + '... http://example.org ...', + '... <a href="http://example.org" class="postlink">http://example.org</a> ...' + ), + array( + '... www.example.org ...', + '... <a href="http://www.example.org" class="postlink">www.example.org</a> ...' + ), + array( + // From make_clickable_test.php + 'www.phpbb.com/community/?', + '<a href="http://www.phpbb.com/community/" class="postlink">www.phpbb.com/community/</a>?' + ), + array( + // From make_clickable_test.php + 'http://www.phpbb.com/community/path/to/long/url/file.ext#section', + '<a href="http://www.phpbb.com/community/path/to/long/url/file.ext#section" class="postlink">http://www.phpbb.com/community/path/to/ ... xt#section</a>' + ), + array( + 'http://localhost/ http://localhost/phpbb/ http://localhost/phpbb/viewforum.php?f=1', + '<a href="http://localhost/" class="postlink">http://localhost/</a> <a href="http://localhost/phpbb/" class="postlink">http://localhost/phpbb/</a> <a href="http://localhost/phpbb/viewforum.php?f=1" class="postlink">viewforum.php?f=1</a>' + ), + array( + 'http://localhost/phpbb/viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + '<a href="http://localhost/phpbb/viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" class="postlink">viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxx ... xxxxxxxxxx</a>' + ), + array( + '[url]http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0[/url]', + '<a href="http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0" class="postlink">http://example.org/0xxxxxxxxxxxxxxxxxxx ... xxxxxxxxx0</a>' + ), + array( + '[URL]http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0[/url]', + '<a href="http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0" class="postlink">http://example.org/0xxxxxxxxxxxxxxxxxxx ... xxxxxxxxx0</a>' + ), + array( + '[url=http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[/url]', + '<a href="http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" class="postlink">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</a>' + ), + array( + '[quote="[url=http://example.org]xxx[/url]"]...[/quote]', + '<blockquote><div><cite><a href="http://example.org" class="postlink">xxx</a> wrote:</cite>...</div></blockquote>' + ), + array( + '[quote="[url]http://example.org[/url]"]...[/quote]', + '<blockquote><div><cite><a href="http://example.org" class="postlink">http://example.org</a> wrote:</cite>...</div></blockquote>' + ), + array( + '[quote=http://example.org]...[/quote]', + '<blockquote><div><cite><a href="http://example.org" class="postlink">http://example.org</a> wrote:</cite>...</div></blockquote>' + ), + array( + "[quote]\nThis is a long quote that is definitely going to exceed 80 characters\n[/quote]\n\nFollowed by a reply", + "<blockquote class=\"uncited\"><div>\nThis is a long quote that is definitely going to exceed 80 characters\n</div></blockquote>\n\nFollowed by a reply" + ), + array( + '[quote=Username post_id=123]...[/quote]', + '<blockquote><div><cite>Username wrote: <a href="phpBB/viewtopic.php?p=123#p123" data-post-id="123" onclick="if(document.getElementById(hash.substr(1)))href=hash">↑</a></cite>...</div></blockquote>' + ), + array( + // Users are not allowed to submit their own URL for the post + '[quote="Username" post_url="http://fake.example.org"]...[/quote]', + '<blockquote><div><cite>Username wrote:</cite>...</div></blockquote>' + ), + array( + '[quote=Username time=58705871]...[/quote]', + '<blockquote><div><cite>Username wrote:<div class="responsive-hide">1971-11-11 11:11:11</div></cite>...</div></blockquote>' + ), + array( + '[quote=Username user_id=123]...[/quote]', + '<blockquote><div><cite><a href="phpBB/memberlist.php?mode=viewprofile&u=123">Username</a> wrote:</cite>...</div></blockquote>' + ), + array( + // Users are not allowed to submit their own URL for the profile + '[quote=Username profile_url=http://fake.example.org]...[/quote]', + '<blockquote><div><cite>Username wrote:</cite>...</div></blockquote>' + ), + array( + // From phpbb_textformatter_s9e_utils_test::test_generate_quote() + '[quote=\'[quote="foo"]\']...[/quote]', + '<blockquote><div><cite>[quote="foo"] wrote:</cite>...</div></blockquote>' + ), + array( + "Emoji: \xF0\x9F\x98\x80", + 'Emoji: <img alt="' . "\xF0\x9F\x98\x80" . '" class="smilies" draggable="false" width="18" height="18" src="//twemoji.maxcdn.com/36x36/1f600.png">' + ), + array( + "Emoji: \xF0\x9F\x98\x80", + "Emoji: \xF0\x9F\x98\x80", + function ($container) + { + $container->get('text_formatter.renderer')->set_viewsmilies(false); + } + ), + ); + } +} diff --git a/tests/text_formatter/s9e/factory_test.php b/tests/text_formatter/s9e/factory_test.php new file mode 100644 index 0000000000..8f8ec7ebc7 --- /dev/null +++ b/tests/text_formatter/s9e/factory_test.php @@ -0,0 +1,253 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +require_once __DIR__ . '/../../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../../phpBB/includes/functions_content.php'; +require_once __DIR__ . '/../../test_framework/phpbb_database_test_case.php'; + +class phpbb_textformatter_s9e_factory_test extends phpbb_database_test_case +{ + public function setUp() + { + $this->cache = new phpbb_mock_cache; + $this->dispatcher = new phpbb_mock_event_dispatcher; + parent::setUp(); + } + + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/factory.xml'); + } + + public function get_cache_dir() + { + return __DIR__ . '/../../tmp/'; + } + + public function get_factory() + { + global $config, $phpbb_root_path, $request, $user; + $this->cache = new phpbb_mock_cache; + $dal = new \phpbb\textformatter\data_access( + $this->new_dbal(), + 'phpbb_bbcodes', + 'phpbb_smilies', + 'phpbb_styles', + 'phpbb_words', + $phpbb_root_path . 'styles/' + ); + $factory = new \phpbb\textformatter\s9e\factory( + $dal, + $this->cache, + $this->dispatcher, + new \phpbb\config\config(array('allowed_schemes_links' => 'http,https,ftp')), + new \phpbb\textformatter\s9e\link_helper, + $this->get_cache_dir(), + '_foo_parser', + '_foo_renderer' + ); + + // Global objects required by generate_board_url() + $config = new \phpbb\config\config(array( + 'script_path' => '/phpbb', + 'server_name' => 'localhost', + 'server_port' => 80, + 'server_protocol' => 'http://', + )); + $request = new phpbb_mock_request; + $user = new phpbb_mock_user; + + return $factory; + } + + public function test_get_configurator() + { + $configurator = $this->get_factory()->get_configurator(); + + $this->assertInstanceOf('s9e\\TextFormatter\\Configurator', $configurator); + + $this->assertTrue(isset($configurator->plugins['Autoemail'])); + $this->assertTrue(isset($configurator->plugins['Autolink'])); + + $this->assertTrue(isset($configurator->BBCodes['B'])); + $this->assertTrue(isset($configurator->BBCodes['CODE'])); + $this->assertTrue(isset($configurator->BBCodes['COLOR'])); + $this->assertTrue(isset($configurator->BBCodes['EMAIL'])); + $this->assertTrue(isset($configurator->BBCodes['FLASH'])); + $this->assertTrue(isset($configurator->BBCodes['I'])); + $this->assertTrue(isset($configurator->BBCodes['IMG'])); + $this->assertTrue(isset($configurator->BBCodes['LIST'])); + $this->assertTrue(isset($configurator->BBCodes['*'])); + $this->assertTrue(isset($configurator->BBCodes['QUOTE'])); + $this->assertTrue(isset($configurator->BBCodes['SIZE'])); + $this->assertTrue(isset($configurator->BBCodes['U'])); + $this->assertTrue(isset($configurator->BBCodes['URL'])); + + // This custom BBCode should be set + $this->assertTrue(isset($configurator->BBCodes['CUSTOM'])); + + $this->assertTrue(isset($configurator->Emoticons[':D'])); + } + + public function test_regenerate() + { + extract($this->get_factory()->regenerate()); + + $this->assertInstanceOf('s9e\\TextFormatter\\Parser', $parser); + $this->assertInstanceOf('s9e\\TextFormatter\\Renderer', $renderer); + + $renderer_data = $this->cache->get('_foo_renderer'); + $this->assertEquals($parser, $this->cache->get('_foo_parser'), 'The parser was not cached'); + $this->assertEquals(get_class($renderer), $renderer_data['class']); + $this->assertInstanceOf('s9e\\TextFormatter\\Plugins\\Censor\\Helper', $renderer_data['censor']); + + $file = $this->get_cache_dir() . get_class($renderer) . '.php'; + $this->assertFileExists($file); + unlink($file); + } + + public function test_tidy() + { + $factory = $this->get_factory(); + + // Create a fake "old" cache file + $old_file = $this->get_cache_dir() . 's9e_foo.php'; + touch($old_file); + + // Create a current renderer + extract($factory->regenerate()); + $new_file = $this->get_cache_dir() . get_class($renderer) . '.php'; + + // Tidy the cache + $factory->tidy(); + + $this->assertFileExists($new_file, 'The current renderer has been deleted'); + $this->assertFileNotExists($old_file, 'The old renderer has not been deleted'); + + unlink($new_file); + } + + public function test_local_url() + { + global $config, $user, $request; + $config = new \phpbb\config\config(array( + 'force_server_vars' => true, + 'server_protocol' => 'http://', + 'server_name' => 'path', + 'server_port' => 80, + 'script_path' => '/to', + 'cookie_secure' => false + )); + $user = new phpbb_mock_user; + $request = new phpbb_mock_request; + + $fixture = __DIR__ . '/fixtures/local_url.xml'; + $renderer = $this->get_test_case_helpers()->set_s9e_services(null, $fixture)->get('text_formatter.renderer'); + + $this->assertSame( + '<a href="http://path/to/foo">http://path/to/foo</a>', + $renderer->render('<r><LOCAL content="foo"><s>[local]</s>foo<e>[/local]</e></LOCAL></r>') + ); + } + + public function test_smilies_special_chars() + { + // Use a smiley that contains every special chars in every field + $fixture = __DIR__ . '/fixtures/smilies_special_chars.xml'; + $renderer = $this->get_test_case_helpers()->set_s9e_services(null, $fixture)->get('text_formatter.renderer'); + + $this->assertSame( + '<img class="smilies" src="phpBB/images/smilies/%22%27%3C&%3E.png" alt=""\'<&>" title=""\'<&>">', + $renderer->render('<r><E>"\'<&></E></r>') + ); + } + + /** + * @testdox {INTTEXT} is supported in custom BBCodes + */ + public function test_inttext_token() + { + $fixture = __DIR__ . '/fixtures/inttext_token.xml'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture); + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + $original = '[spoiler=ɎɆS]text[/spoiler]'; + $expected = '<div class="spoiler"><div class="title">ɎɆS</div><div class="content">text</div></div>'; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + + $original = '[spoiler=N:O:P:E]text[/spoiler]'; + $expected = $original; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + } + + /** + * @testdox Preserves comments in custom BBCodes + */ + public function test_preserve_comments() + { + $fixture = __DIR__ . '/fixtures/preserve_comments.xml'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture); + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + $original = '[X]'; + $expected = '<!-- comment -->'; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + } + + /** + * @testdox Accepts unsafe custom BBCodes + */ + public function test_unsafe_bbcode() + { + $fixture = __DIR__ . '/fixtures/unsafe_bbcode.xml'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture); + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + $original = '[xss=javascript:alert(1)]text[/xss]'; + $expected = '<a href="javascript:alert(1)">text</a>'; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + } + + /** + * @testdox get_configurator() triggers events before and after configuration + */ + public function test_configure_events() + { + $this->dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $this->dispatcher + ->expects($this->at(0)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_configure_before', + $this->callback(array($this, 'configure_event_callback')) + ) + ->will($this->returnArgument(1)); + $this->dispatcher + ->expects($this->at(1)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_configure_after', + $this->callback(array($this, 'configure_event_callback')) + ) + ->will($this->returnArgument(1)); + + $this->get_factory()->get_configurator(); + } + + public function configure_event_callback($vars) + { + return isset($vars['configurator']) && $vars['configurator'] instanceof \s9e\TextFormatter\Configurator; + } +} diff --git a/tests/text_formatter/s9e/fixtures/default_formatting.xml b/tests/text_formatter/s9e/fixtures/default_formatting.xml new file mode 100644 index 0000000000..2b7236fb30 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/default_formatting.xml @@ -0,0 +1,466 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>1</value> + <value>:D</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>1</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>:-D</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>1</value> + </row> + <row> + <value>3</value> + <value>:grin:</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>3</value> + <value>1</value> + </row> + <row> + <value>4</value> + <value>:)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>4</value> + <value>1</value> + </row> + <row> + <value>5</value> + <value>:-)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>5</value> + <value>1</value> + </row> + <row> + <value>6</value> + <value>:smile:</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>6</value> + <value>1</value> + </row> + <row> + <value>7</value> + <value>;)</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>7</value> + <value>1</value> + </row> + <row> + <value>8</value> + <value>;-)</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>8</value> + <value>1</value> + </row> + <row> + <value>9</value> + <value>:wink:</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>9</value> + <value>1</value> + </row> + <row> + <value>10</value> + <value>:(</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>10</value> + <value>1</value> + </row> + <row> + <value>11</value> + <value>:-(</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>11</value> + <value>1</value> + </row> + <row> + <value>12</value> + <value>:sad:</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>12</value> + <value>1</value> + </row> + <row> + <value>13</value> + <value>:o</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>13</value> + <value>1</value> + </row> + <row> + <value>14</value> + <value>:-o</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>14</value> + <value>1</value> + </row> + <row> + <value>15</value> + <value>:eek:</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>15</value> + <value>1</value> + </row> + <row> + <value>16</value> + <value>:shock:</value> + <value>Shocked</value> + <value>icon_eek.gif</value> + <value>15</value> + <value>17</value> + <value>16</value> + <value>1</value> + </row> + <row> + <value>17</value> + <value>:?</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>17</value> + <value>1</value> + </row> + <row> + <value>18</value> + <value>:-?</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>18</value> + <value>1</value> + </row> + <row> + <value>19</value> + <value>:???:</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>19</value> + <value>1</value> + </row> + <row> + <value>20</value> + <value>8-)</value> + <value>Cool</value> + <value>icon_cool.gif</value> + <value>15</value> + <value>17</value> + <value>20</value> + <value>1</value> + </row> + <row> + <value>21</value> + <value>:cool:</value> + <value>Cool</value> + <value>icon_cool.gif</value> + <value>15</value> + <value>17</value> + <value>21</value> + <value>1</value> + </row> + <row> + <value>22</value> + <value>:lol:</value> + <value>Laughing</value> + <value>icon_lol.gif</value> + <value>15</value> + <value>17</value> + <value>22</value> + <value>1</value> + </row> + <row> + <value>23</value> + <value>:x</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>23</value> + <value>1</value> + </row> + <row> + <value>24</value> + <value>:-x</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>24</value> + <value>1</value> + </row> + <row> + <value>25</value> + <value>:mad:</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>25</value> + <value>1</value> + </row> + <row> + <value>26</value> + <value>:P</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>26</value> + <value>1</value> + </row> + <row> + <value>27</value> + <value>:-P</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>27</value> + <value>1</value> + </row> + <row> + <value>28</value> + <value>:razz:</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>28</value> + <value>1</value> + </row> + <row> + <value>29</value> + <value>:oops:</value> + <value>Embarrassed</value> + <value>icon_redface.gif</value> + <value>15</value> + <value>17</value> + <value>29</value> + <value>1</value> + </row> + <row> + <value>30</value> + <value>:cry:</value> + <value>Crying or Very Sad</value> + <value>icon_cry.gif</value> + <value>15</value> + <value>17</value> + <value>30</value> + <value>1</value> + </row> + <row> + <value>31</value> + <value>:evil:</value> + <value>Evil or Very Mad</value> + <value>icon_evil.gif</value> + <value>15</value> + <value>17</value> + <value>31</value> + <value>1</value> + </row> + <row> + <value>32</value> + <value>:twisted:</value> + <value>Twisted Evil</value> + <value>icon_twisted.gif</value> + <value>15</value> + <value>17</value> + <value>32</value> + <value>1</value> + </row> + <row> + <value>33</value> + <value>:roll:</value> + <value>Rolling Eyes</value> + <value>icon_rolleyes.gif</value> + <value>15</value> + <value>17</value> + <value>33</value> + <value>1</value> + </row> + <row> + <value>34</value> + <value>:!:</value> + <value>Exclamation</value> + <value>icon_exclaim.gif</value> + <value>15</value> + <value>17</value> + <value>34</value> + <value>1</value> + </row> + <row> + <value>35</value> + <value>:?:</value> + <value>Question</value> + <value>icon_question.gif</value> + <value>15</value> + <value>17</value> + <value>35</value> + <value>1</value> + </row> + <row> + <value>36</value> + <value>:idea:</value> + <value>Idea</value> + <value>icon_idea.gif</value> + <value>15</value> + <value>17</value> + <value>36</value> + <value>1</value> + </row> + <row> + <value>37</value> + <value>:arrow:</value> + <value>Arrow</value> + <value>icon_arrow.gif</value> + <value>15</value> + <value>17</value> + <value>37</value> + <value>1</value> + </row> + <row> + <value>38</value> + <value>:|</value> + <value>Neutral</value> + <value>icon_neutral.gif</value> + <value>15</value> + <value>17</value> + <value>38</value> + <value>1</value> + </row> + <row> + <value>39</value> + <value>:-|</value> + <value>Neutral</value> + <value>icon_neutral.gif</value> + <value>15</value> + <value>17</value> + <value>39</value> + <value>1</value> + </row> + <row> + <value>40</value> + <value>:mrgreen:</value> + <value>Mr. Green</value> + <value>icon_mrgreen.gif</value> + <value>15</value> + <value>17</value> + <value>40</value> + <value>1</value> + </row> + <row> + <value>41</value> + <value>:geek:</value> + <value>Geek</value> + <value>icon_e_geek.gif</value> + <value>17</value> + <value>17</value> + <value>41</value> + <value>1</value> + </row> + <row> + <value>42</value> + <value>:ugeek:</value> + <value>Uber Geek</value> + <value>icon_e_ugeek.gif</value> + <value>17</value> + <value>18</value> + <value>42</value> + <value>1</value> + </row> + </table> + + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + <row> + <value>1</value> + <value>prosilver</value> + <value>&copy; phpBB Group</value> + <value>1</value> + <value>prosilver</value> + <value>kNg=</value> + <value>0</value> + <value></value> + </row> + </table> + + <table name="phpbb_words"> + <column>word_id</column> + <column>word</column> + <column>replacement</column> + + <row> + <value>1</value> + <value>apple</value> + <value>banana</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/default_lang.xml b/tests/text_formatter/s9e/fixtures/default_lang.xml new file mode 100644 index 0000000000..2cfde4aab2 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/default_lang.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + + <row> + <value>13</value> + <value>foo</value> + <value></value> + <value>1</value> + <value>[foo]{TEXT}[/foo]</value> + <value>{L_FOO_BAR}</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/factory.xml b/tests/text_formatter/s9e/fixtures/factory.xml new file mode 100644 index 0000000000..9ae52e9747 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/factory.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>custom</value> + <value></value> + <value>1</value> + <value>[custom]{TEXT}[/custom]</value> + <value><span style="color:red">{TEXT}</span></value> + <value>!\[custom\](.*?)\[/custom\]!ies</value> + <value>'[custom:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/custom:$uid]'</value> + <value>!\[custom:$uid\](.*?)\[/custom:$uid\]!s</value> + <value><span style="color:red">${1}</span></value> + </row> + <row> + <value>14</value> + <value>unsafe</value> + <value></value> + <value>1</value> + <value>[unsafe]{TEXT}[/unsafe]</value> + <value><script>{TEXT}</script></value> + <value>!\[unsafe\](.*?)\[/unsafe\]!ies</value> + <value>'[unsafe:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/unsafe:$uid]'</value> + <value>!\[unsafe:$uid\](.*?)\[/unsafe:$uid\]!s</value> + <value><script>${1}</script></value> + </row> + </table> + + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>1</value> + <value>:D</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>1</value> + </row> + <row> + <value>4</value> + <value>:)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>4</value> + <value>1</value> + </row> + <row> + <value>10</value> + <value>:(</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>10</value> + <value>1</value> + </row> + </table> + + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + + <row> + <value>1</value> + <value>prosilver</value> + <value>&copy; phpBB Group</value> + <value>1</value> + <value>prosilver</value> + <value>kNg=</value> + <value>0</value> + <value></value> + </row> + </table> + + <table name="phpbb_words"> + <column>word_id</column> + <column>word</column> + <column>replacement</column> + + <row> + <value>1</value> + <value>apple</value> + <value>banana</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/inttext_token.xml b/tests/text_formatter/s9e/fixtures/inttext_token.xml new file mode 100644 index 0000000000..30b971f315 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/inttext_token.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>spoiler=</value> + <value></value> + <value>1</value> + <value>[spoiler={INTTEXT}]{TEXT}[/spoiler]</value> + <value><![CDATA[<div class="spoiler"><div class="title">{INTTEXT}</div><div class="content">{TEXT}</div></div>]]></value> + <value><![CDATA[!\[spoiler\=([\p{L}\p{N}\-+,_. ]+)\](.*?)\[/spoiler\]!iues]]></value> + <value><![CDATA['[spoiler=${1}:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${2}')).'[/spoiler:$uid]']]></value> + <value><![CDATA[!\[spoiler\=([\p{L}\p{N}\-+,_. ]+):$uid\](.*?)\[/spoiler:$uid\]!su]]></value><value><![CDATA[<div class="spoiler"><div class="title">${1}</div><div class="content">${2}</div></div>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/local_url.xml b/tests/text_formatter/s9e/fixtures/local_url.xml new file mode 100644 index 0000000000..9db2bf4710 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/local_url.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>local</value> + <value></value> + <value>1</value> + <value>[local]{LOCAL_URL}[/local]</value> + <value><![CDATA[<a href="{LOCAL_URL}">{LOCAL_URL}</a>]]></value> + <value><*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:#(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?)\[/local\]!ie]]></value> + <value><![CDATA['[local:$uid]'.$this->bbcode_specialchars('${1}').'[/local:$uid]']]></value> + <value><((?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:#(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?)(?-i)\[/local:$uid\]!s]]></value> + <value><![CDATA[<a href="http://path/to/phpBB/${1}">http://path/to/phpBB/${1}</a>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/preserve_comments.xml b/tests/text_formatter/s9e/fixtures/preserve_comments.xml new file mode 100644 index 0000000000..f81d366aad --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/preserve_comments.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>X</value> + <value></value> + <value>1</value> + <value>[X][/X]</value> + <value><![CDATA[<!-- comment -->]]></value> + <value><![CDATA[!\[x\]\[/x\]!i]]></value> + <value><![CDATA[[x:$uid][/x:$uid]]]></value> + <value><![CDATA[[x:$uid][/x:$uid]]]></value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml b/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml new file mode 100644 index 0000000000..d3a7cfa4f7 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>1</value> + <value>"'<&></value> + <value>"'<&></value> + <value>"'<&>.png</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>1</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/style_inheritance.xml b/tests/text_formatter/s9e/fixtures/style_inheritance.xml new file mode 100644 index 0000000000..a692d0ef2d --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/style_inheritance.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + + <row> + <value>1</value> + <value>foo</value> + <value></value> + <value>1</value> + <value>foo</value> + <!-- Bitfield for "b" only --> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + <row> + <value>2</value> + <value>fooplus</value> + <value></value> + <value>1</value> + <value>fooplus</value> + <value>QA==</value> + <value>1</value> + <value></value> + </row> + <row> + <value>3</value> + <value>fooplusplus</value> + <value></value> + <value>1</value> + <value>fooplusplus</value> + <value>QA==</value> + <value>2</value> + <value></value> + </row> + <row> + <value>4</value> + <value>bar</value> + <value></value> + <value>1</value> + <value>bar</value> + <!-- Bitfield for "b" only --> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + <row> + <value>5</value> + <value>barplus</value> + <value></value> + <value>1</value> + <value>barplus</value> + <value>QA==</value> + <value>4</value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/styles.xml b/tests/text_formatter/s9e/fixtures/styles.xml new file mode 100644 index 0000000000..8004412aea --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + + <row> + <value>1</value> + <value>foo</value> + <value></value> + <value>1</value> + <value>foo</value> + <!-- Bitfield for "b" only --> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + <row> + <value>2</value> + <value>bar</value> + <value></value> + <value>1</value> + <value>bar</value> + <!-- Bitfield for "b" only --> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html new file mode 100644 index 0000000000..76a35542be --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html @@ -0,0 +1,40 @@ +<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open --> +<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default --> +<!-- BEGIN ulist_close --></ul><!-- END ulist_close --> + +<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open --> +<!-- BEGIN olist_close --></ol><!-- END olist_close --> + +<!-- BEGIN listitem --><li><!-- END listitem --> +<!-- BEGIN listitem_close --></li><!-- END listitem_close --> + +<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open --> +<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open --> +<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close --> + +<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open --> +<!-- BEGIN code_close --></code></div><!-- END code_close --> + +<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open --> +<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close --> + +<!-- BEGIN b_open --><b><!-- END b_open --> +<!-- BEGIN b_close --></b><!-- END b_close --> + +<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open --> +<!-- BEGIN u_close --></span><!-- END u_close --> + +<!-- BEGIN i_open --><em><!-- END i_open --> +<!-- BEGIN i_close --></em><!-- END i_close --> + +<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color --> + +<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size --> + +<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img --> + +<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url --> + +<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email --> + +<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash --> diff --git a/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html new file mode 100644 index 0000000000..fad8d828fd --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html @@ -0,0 +1,40 @@ +<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open --> +<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default --> +<!-- BEGIN ulist_close --></ul><!-- END ulist_close --> + +<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open --> +<!-- BEGIN olist_close --></ol><!-- END olist_close --> + +<!-- BEGIN listitem --><li><!-- END listitem --> +<!-- BEGIN listitem_close --></li><!-- END listitem_close --> + +<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open --> +<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open --> +<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close --> + +<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open --> +<!-- BEGIN code_close --></code></div><!-- END code_close --> + +<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open --> +<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close --> + +<!-- BEGIN b_open --><b class="barplus"><!-- END b_open --> +<!-- BEGIN b_close --></b><!-- END b_close --> + +<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open --> +<!-- BEGIN u_close --></span><!-- END u_close --> + +<!-- BEGIN i_open --><em><!-- END i_open --> +<!-- BEGIN i_close --></em><!-- END i_close --> + +<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color --> + +<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size --> + +<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img --> + +<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url --> + +<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email --> + +<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash --> diff --git a/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html new file mode 100644 index 0000000000..3e38d13a32 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html @@ -0,0 +1,40 @@ +<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open --> +<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default --> +<!-- BEGIN ulist_close --></ul><!-- END ulist_close --> + +<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open --> +<!-- BEGIN olist_close --></ol><!-- END olist_close --> + +<!-- BEGIN listitem --><li><!-- END listitem --> +<!-- BEGIN listitem_close --></li><!-- END listitem_close --> + +<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open --> +<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open --> +<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close --> + +<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open --> +<!-- BEGIN code_close --></code></div><!-- END code_close --> + +<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open --> +<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close --> + +<!-- BEGIN b_open --><strong><!-- END b_open --> +<!-- BEGIN b_close --></strong><!-- END b_close --> + +<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open --> +<!-- BEGIN u_close --></span><!-- END u_close --> + +<!-- BEGIN i_open --><em><!-- END i_open --> +<!-- BEGIN i_close --></em><!-- END i_close --> + +<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color --> + +<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size --> + +<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img --> + +<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url --> + +<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email --> + +<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash --> diff --git a/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml b/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml new file mode 100644 index 0000000000..55a2e689b6 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>xss=</value> + <value></value> + <value>1</value> + <value>[xss={TEXT1}]{TEXT2}[/xss]</value> + <value><![CDATA[<a href="{TEXT1}">{TEXT2}</a>]]></value> + <value><\[/xss\]!ies]]></value> + <value><![CDATA['[xss='.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${1}')).':$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${2}')).'[/xss:$uid]']]></value> + <value><\[/xss:$uid\]!s]]></value> + <value><![CDATA[<a href="${1}">${2}</a>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/parser_test.php b/tests/text_formatter/s9e/parser_test.php new file mode 100644 index 0000000000..3b72e713e1 --- /dev/null +++ b/tests/text_formatter/s9e/parser_test.php @@ -0,0 +1,260 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +require_once __DIR__ . '/../../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../../phpBB/includes/functions_content.php'; + +class phpbb_textformatter_s9e_parser_test extends phpbb_test_case +{ + public function test_load_from_cache() + { + $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser') + ->disableOriginalConstructor() + ->getMock(); + + $cache = $this->getMock('phpbb_mock_cache'); + $cache->expects($this->once()) + ->method('get') + ->with('_foo_parser') + ->will($this->returnValue($mock)); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->never())->method('regenerate'); + + $parser = new \phpbb\textformatter\s9e\parser( + $cache, + '_foo_parser', + $factory, + new phpbb_mock_event_dispatcher + ); + } + + public function test_use_from_cache() + { + $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser') + ->disableOriginalConstructor() + ->getMock(); + + $mock->expects($this->once()) + ->method('parse') + ->with('test') + ->will($this->returnValue('<t>test</t>')); + + $cache = new phpbb_mock_cache; + $cache->put('_foo_parser', $mock); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->never())->method('regenerate'); + + $parser = new \phpbb\textformatter\s9e\parser( + $cache, + '_foo_parser', + $factory, + new phpbb_mock_event_dispatcher + ); + + $this->assertSame('<t>test</t>', $parser->parse('test')); + } + + public function test_regenerate_on_cache_miss() + { + $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser') + ->disableOriginalConstructor() + ->getMock(); + + $mock->expects($this->once()) + ->method('parse') + ->with('test') + ->will($this->returnValue('<t>test</t>')); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->once()) + ->method('regenerate') + ->will($this->returnValue(array('parser' => $mock))); + + $parser = new \phpbb\textformatter\s9e\parser( + new phpbb_mock_cache, + '_foo_parser', + $factory, + new phpbb_mock_event_dispatcher + ); + + $this->assertSame('<t>test</t>', $parser->parse('test')); + } + + /** + * @dataProvider get_options_tests() + */ + public function test_options($adapter_method, $adapter_arg, $concrete_method, $concrete_arg) + { + $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser') + ->setMethods(array($concrete_method)) + ->disableOriginalConstructor() + ->getMock(); + foreach ((array) $concrete_arg as $i => $concrete_arg) + { + $mock->expects($this->at($i)) + ->method($concrete_method) + ->with($concrete_arg); + } + + $cache = new phpbb_mock_cache; + $cache->put('_foo_parser', $mock); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + + $parser = new \phpbb\textformatter\s9e\parser( + $cache, + '_foo_parser', + $factory, + new phpbb_mock_event_dispatcher + ); + + call_user_func_array(array($parser, $adapter_method), (array) $adapter_arg); + } + + public function get_options_tests() + { + return array( + array( + 'disable_bbcode', 'url', + 'disableTag', 'URL' + ), + array( + 'disable_bbcodes', null, + 'disablePlugin', 'BBCodes' + ), + array( + 'disable_magic_url', null, + 'disablePlugin', array('Autoemail', 'Autolink') + ), + array( + 'disable_smilies', null, + 'disablePlugin', 'Emoticons' + ), + array( + 'enable_bbcode', 'url', + 'enableTag', 'URL' + ), + array( + 'enable_bbcodes', null, + 'enablePlugin', 'BBCodes' + ), + array( + 'enable_magic_url', null, + 'enablePlugin', array('Autoemail', 'Autolink') + ), + array( + 'enable_smilies', null, + 'enablePlugin', 'Emoticons' + ) + ); + } + + /** + * @testdox The constructor triggers a core.text_formatter_s9e_parser_setup event + */ + public function test_setup_event() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $dispatcher + ->expects($this->once()) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_parser_setup', + $this->callback(array($this, 'setup_event_callback')) + ) + ->will($this->returnArgument(1)); + + new \phpbb\textformatter\s9e\parser( + $container->get('cache.driver'), + '_foo_parser', + $container->get('text_formatter.s9e.factory'), + $dispatcher + ); + } + + public function setup_event_callback($vars) + { + return isset($vars['parser']) + && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser; + } + + /** + * @testdox parse() triggers a core.text_formatter_s9e_parse_before and core.text_formatter_s9e_parse_after events + */ + public function test_parse_event() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $dispatcher + ->expects($this->any()) + ->method('trigger_event') + ->will($this->returnArgument(1)); + $dispatcher + ->expects($this->at(1)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_parse_before', + $this->callback(array($this, 'parse_before_event_callback')) + ) + ->will($this->returnArgument(1)); + $dispatcher + ->expects($this->at(2)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_parse_after', + $this->callback(array($this, 'parse_after_event_callback')) + ) + ->will($this->returnArgument(1)); + + $parser = new \phpbb\textformatter\s9e\parser( + $container->get('cache.driver'), + '_foo_parser', + $container->get('text_formatter.s9e.factory'), + $dispatcher + ); + $parser->parse('...'); + } + + public function parse_before_event_callback($vars) + { + return isset($vars['parser']) + && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser + && isset($vars['text']) + && $vars['text'] === '...'; + } + + public function parse_after_event_callback($vars) + { + return isset($vars['parser']) + && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser + && isset($vars['xml']) + && $vars['xml'] === '<t>...</t>'; + } + + public function test_get_parser() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $parser = $container->get('text_formatter.parser'); + $this->assertInstanceOf('s9e\\TextFormatter\\Parser', $parser->get_parser()); + } +} diff --git a/tests/text_formatter/s9e/renderer_test.php b/tests/text_formatter/s9e/renderer_test.php new file mode 100644 index 0000000000..ad5bfa78fc --- /dev/null +++ b/tests/text_formatter/s9e/renderer_test.php @@ -0,0 +1,483 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +require_once __DIR__ . '/../../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../../phpBB/includes/functions_content.php'; + +class phpbb_textformatter_s9e_renderer_test extends phpbb_test_case +{ + public function get_cache_dir() + { + return __DIR__ . '/../../tmp/'; + } + + public function test_load_from_cache() + { + // Save a fake renderer class in the cache dir + file_put_contents( + $this->get_cache_dir() . 'renderer_foo.php', + '<?php class renderer_foo { public function setParameter() {} }' + ); + + $cache = $this->getMock('phpbb_mock_cache'); + $cache->expects($this->once()) + ->method('get') + ->with('_foo_renderer') + ->will($this->returnValue(array('class' => 'renderer_foo'))); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->never())->method('regenerate'); + + $renderer = new \phpbb\textformatter\s9e\renderer( + $cache, + $this->get_cache_dir(), + '_foo_renderer', + $factory, + new phpbb_mock_event_dispatcher + ); + } + + public function test_regenerate_on_cache_miss() + { + $mock = $this->getMockForAbstractClass('s9e\\TextFormatter\\Renderer'); + + $cache = $this->getMock('phpbb_mock_cache'); + $cache->expects($this->once()) + ->method('get') + ->with('_foo_renderer') + ->will($this->returnValue(false)); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->once()) + ->method('regenerate') + ->will($this->returnValue(array('parser' => $mock))); + + $renderer = new \phpbb\textformatter\s9e\renderer( + $cache, + $this->get_cache_dir(), + '_foo_renderer', + $factory, + new phpbb_mock_event_dispatcher + ); + } + + /** + * @dataProvider get_options_cases + */ + public function test_options($original, $expected, $calls) + { + $container = new phpbb_mock_container_builder; + $this->get_test_case_helpers()->set_s9e_services($container); + + $renderer = $container->get('text_formatter.renderer'); + + foreach ($calls as $method => $arg) + { + $renderer->$method($arg); + } + + $this->assertSame($expected, $renderer->render($original)); + } + + public function get_options_cases() + { + return array( + array( + '<t>apple</t>', + 'banana', + array('set_viewcensors' => true) + ), + array( + '<t>apple</t>', + 'apple', + array('set_viewcensors' => false) + ), + array( + '<r><FLASH height="456" url="http://example.org/foo.swf" width="123"><s>[flash=123,456]</s><URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL><e>[/flash]</e></FLASH></r>', + '<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="123" height="456"><param name="movie" value="http://example.org/foo.swf"><param name="play" value="false"><param name="loop" value="false"><param name="quality" value="high"><param name="allowScriptAccess" value="never"><param name="allowNetworking" value="internal"><embed src="http://example.org/foo.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="123" height="456" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></object>', + array('set_viewflash' => true) + ), + array( + '<r><IMG src="http://example.org/foo.png"><s>[img]</s>http://example.org/foo.png<e>[/img]</e></IMG></r>', + '<img src="http://example.org/foo.png" class="postimage" alt="Image">', + array('set_viewimg' => true) + ), + array( + '<r><E>:)</E></r>', + '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" alt=":)" title="Smile">', + array('set_viewsmilies' => true) + ), + array( + '<r><E>:)</E></r>', + ':)', + array('set_viewsmilies' => false) + ), + ); + } + + /** + * @dataProvider get_default_options_cases + */ + public function test_default_options($original, $expected, $setup = null) + { + $container = new phpbb_mock_container_builder; + + if (isset($setup)) + { + $setup($container, $this); + } + + $this->get_test_case_helpers()->set_s9e_services($container); + + $this->assertSame($expected, $container->get('text_formatter.renderer')->render($original)); + } + + public function get_default_options_cases() + { + return array( + array( + '<t>apple</t>', + 'banana' + ), + array( + '<t>apple</t>', + 'banana', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewcensors', false); + + $phpbb_container->set('user', $user); + } + ), + array( + '<t>apple</t>', + 'banana', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewcensors', false); + + $config = new \phpbb\config\config(array('allow_nocensors' => true)); + + $phpbb_container->set('user', $user); + $phpbb_container->set('config', $config); + } + ), + array( + '<t>apple</t>', + 'apple', + function ($phpbb_container, $test) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewcensors', false); + + $config = new \phpbb\config\config(array('allow_nocensors' => true)); + + $auth = $test->getMock('phpbb\\auth\\auth'); + $auth->expects($test->any()) + ->method('acl_get') + ->with('u_chgcensors') + ->will($test->returnValue(true)); + + $phpbb_container->set('user', $user); + $phpbb_container->set('config', $config); + $phpbb_container->set('auth', $auth); + } + ), + array( + '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>', + '<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="123" height="456"><param name="movie" value="http://localhost/foo.swf"><param name="play" value="false"><param name="loop" value="false"><param name="quality" value="high"><param name="allowScriptAccess" value="never"><param name="allowNetworking" value="internal"><embed src="http://localhost/foo.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="123" height="456" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></object>' + ), + array( + '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>', + 'http://localhost/foo.swf', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewflash', false); + + $phpbb_container->set('user', $user); + } + ), + array( + '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>', + '<img src="http://localhost/mrgreen.gif" class="postimage" alt="Image">' + ), + array( + '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>', + '<a href="http://localhost/mrgreen.gif" class="postlink">http://localhost/mrgreen.gif</a>', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewimg', false); + + $phpbb_container->set('user', $user); + } + ), + array( + '<r><E>:)</E></r>', + '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" alt=":)" title="Smile">' + ), + array( + '<r><E>:)</E></r>', + ':)', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('smilies', false); + + $phpbb_container->set('user', $user); + } + ), + ); + } + + public function test_default_lang() + { + global $phpbb_container; + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/default_lang.xml'); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + + $this->assertSame('FOO_BAR', $renderer->render('<r><FOO/></r>')); + } + + /** + * @dataProvider get_option_names + */ + public function test_get_option($option_name) + { + global $phpbb_container; + $this->get_test_case_helpers()->set_s9e_services(); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + + $renderer->{'set_' . $option_name}(false); + $this->assertFalse($renderer->{'get_' . $option_name}()); + $renderer->{'set_' . $option_name}(true); + $this->assertTrue($renderer->{'get_' . $option_name}()); + } + + public function get_option_names() + { + return array( + array('viewcensors'), + array('viewflash'), + array('viewimg'), + array('viewsmilies') + ); + } + + public function test_styles() + { + global $phpbb_container; + + $tests = array( + 1 => '<strong>bold</strong>', + 2 => '<b>bold</b>' + ); + + global $phpbb_root_path, $phpEx; + + foreach ($tests as $style_id => $expected) + { + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->style = array('style_id' => $style_id); + + $phpbb_container = new phpbb_mock_container_builder; + $phpbb_container->set('user', $user); + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/styles.xml', __DIR__ . '/fixtures/styles/'); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + $this->assertSame( + $expected, + $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>') + ); + } + } + + public function test_style_inheritance1() + { + global $phpbb_container, $phpbb_root_path, $phpEx; + + // Style 3 inherits from 2 which inherits from 1. Only style 1 has a bbcode.html + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->style = array('style_id' => 3); + + $phpbb_container = new phpbb_mock_container_builder; + $phpbb_container->set('user', $user); + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/style_inheritance.xml', __DIR__ . '/fixtures/styles/'); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + $this->assertSame( + '<strong>bold</strong>', + $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>') + ); + } + + public function test_style_inheritance2() + { + global $phpbb_container, $phpbb_root_path, $phpEx; + + // Style 5 inherits from 4, but both have a bbcode.html + $tests = array( + 4 => '<b>bold</b>', + 5 => '<b class="barplus">bold</b>' + ); + + foreach ($tests as $style_id => $expected) + { + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->style = array('style_id' => $style_id); + + $phpbb_container = new phpbb_mock_container_builder; + $phpbb_container->set('user', $user); + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/style_inheritance.xml', __DIR__ . '/fixtures/styles/'); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + $this->assertSame( + $expected, + $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>') + ); + } + } + + /** + * @testdox The constructor triggers a core.text_formatter_s9e_renderer_setup event + */ + public function test_setup_event() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $dispatcher + ->expects($this->once()) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_renderer_setup', + $this->callback(array($this, 'setup_event_callback')) + ) + ->will($this->returnArgument(1)); + + new \phpbb\textformatter\s9e\renderer( + $container->get('cache.driver'), + $container->getParameter('cache.dir'), + '_foo_renderer', + $container->get('text_formatter.s9e.factory'), + $dispatcher + ); + } + + public function setup_event_callback($vars) + { + return isset($vars['renderer']) + && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer; + } + + /** + * @testdox render() triggers a core.text_formatter_s9e_render_before and core.text_formatter_s9e_render_after events + */ + public function test_render_event() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $dispatcher + ->expects($this->any()) + ->method('trigger_event') + ->will($this->returnArgument(1)); + $dispatcher + ->expects($this->at(1)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_render_before', + $this->callback(array($this, 'render_before_event_callback')) + ) + ->will($this->returnArgument(1)); + $dispatcher + ->expects($this->at(2)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_render_after', + $this->callback(array($this, 'render_after_event_callback')) + ) + ->will($this->returnArgument(1)); + + $renderer = new \phpbb\textformatter\s9e\renderer( + $container->get('cache.driver'), + $container->getParameter('cache.dir'), + '_foo_renderer', + $container->get('text_formatter.s9e.factory'), + $dispatcher + ); + $renderer->render('<t>...</t>'); + } + + public function render_before_event_callback($vars) + { + return isset($vars['renderer']) + && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer + && isset($vars['xml']) + && $vars['xml'] === '<t>...</t>'; + } + + public function render_after_event_callback($vars) + { + return isset($vars['html']) + && $vars['html'] === '...' + && isset($vars['renderer']) + && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer; + } + + public function test_get_renderer() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $renderer = $container->get('text_formatter.renderer'); + $this->assertInstanceOf('s9e\\TextFormatter\\Renderer', $renderer->get_renderer()); + } +} diff --git a/tests/text_formatter/s9e/utils_test.php b/tests/text_formatter/s9e/utils_test.php new file mode 100644 index 0000000000..dade259790 --- /dev/null +++ b/tests/text_formatter/s9e/utils_test.php @@ -0,0 +1,279 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once __DIR__ . '/../../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../../phpBB/includes/functions_content.php'; + +class phpbb_textformatter_s9e_utils_test extends phpbb_test_case +{ + /** + * @dataProvider get_unparse_tests + */ + public function test_unparse($original, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $utils = $container->get('text_formatter.utils'); + + $this->assertSame($expected, $utils->unparse($original)); + } + + public function get_unparse_tests() + { + return array( + array( + '<t>Plain text</t>', + 'Plain text' + ), + array( + "<t>Multi<br/>\nline</t>", + "Multi\nline" + ), + array( + '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>', + '[b]bold[/b]' + ) + ); + } + + /** + * @dataProvider get_clean_formatting_tests + */ + public function test_clean_formatting($original, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $utils = $container->get('text_formatter.utils'); + + $this->assertSame($expected, $utils->clean_formatting($original)); + } + + public function get_clean_formatting_tests() + { + return array( + array( + '<t>Plain text</t>', + 'Plain text' + ), + array( + "<t>Multi<br/>\nline</t>", + "Multi\nline" + ), + array( + '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>', + ' bold ' + ) + ); + } + + /** + * @dataProvider get_outermost_quote_authors_tests + */ + public function test_get_outermost_quote_authors($original, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $utils = $container->get('text_formatter.utils'); + $parser = $container->get('text_formatter.parser'); + + $this->assertSame($expected, $utils->get_outermost_quote_authors($parser->parse($original))); + } + + public function get_outermost_quote_authors_tests() + { + return array( + array( + 'No quotes here', + array() + ), + array( + '[quote="foo"]..[/quote] [quote]..[/quote]', + array('foo') + ), + array( + '[quote=foo]..[/quote] [quote]..[/quote]', + array('foo') + ), + array( + '[quote=foo]..[/quote] [quote=bar]..[/quote]', + array('foo', 'bar') + ), + array( + '[quote=foo].[quote=baz]..[/quote].[/quote] [quote=bar]..[/quote]', + array('foo', 'bar') + ), + ); + } + + /** + * @dataProvider get_generate_quote_tests + */ + public function test_generate_quote($text, $params, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $utils = $container->get('text_formatter.utils'); + + $this->assertSame($expected, $utils->generate_quote($text, $params)); + } + + public function get_generate_quote_tests() + { + return array( + array( + '...', + array(), + '[quote]...[/quote]', + ), + array( + '...', + array('author' => 'Brian Kibler'), + '[quote="Brian Kibler"]...[/quote]', + ), + array( + '...', + array('author' => 'Brian "Brian Kibler" Kibler of Brian Kibler Gaming'), + '[quote=\'Brian "Brian Kibler" Kibler of Brian Kibler Gaming\']...[/quote]', + ), + array( + '...', + array('author' => "Brian Kibler Gaming's Brian Kibler"), + '[quote="Brian Kibler Gaming\'s Brian Kibler"]...[/quote]', + ), + array( + '...', + array('author' => "\\\"'"), + '[quote="\\\\\\"\'"]...[/quote]', + ), + array( + '...', + array('author' => 'Lots of doubles """ one single \' one backslash \\'), + '[quote=\'Lots of doubles """ one single \\\' one backslash \\\\\']...[/quote]', + ), + array( + '...', + array('author' => "Lots of singles ''' one double \" one backslash \\"), + '[quote="Lots of singles \'\'\' one double \\" one backslash \\\\"]...[/quote]', + ), + array( + '...', + array('author' => 'Defaults to doublequotes """\'\'\''), + '[quote="Defaults to doublequotes \\"\\"\\"\'\'\'"]...[/quote]', + ), + array( + '...', + array( + 'author' => 'user', + 'post_id' => 123, + 'url' => 'http://example.org' + ), + '[quote=user post_id=123 url=http://example.org]...[/quote]', + ), + array( + '...', + array( + 'author' => 'user', + 'post_id' => 123, + 'user_id' => ANONYMOUS + ), + '[quote=user post_id=123]...[/quote]', + ), + array( + '...', + array('author' => ' '), + '[quote=" "]...[/quote]', + ), + array( + '...', + array('author' => 'foo bar'), + '[quote="foo bar"]...[/quote]', + ), + array( + '...', + array('author' => '\\'), + '[quote="\\\\"]...[/quote]', + ), + array( + '...', + array('author' => '[quote="foo"]'), + '[quote=\'[quote="foo"]\']...[/quote]', + ), + array( + '...', + array('author' => '""'), + '[quote=\'""\']...[/quote]', + ), + array( + '...', + array('author' => "''"), + '[quote="\'\'"]...[/quote]', + ), + array( + 'This is a long quote that is definitely going to exceed 80 characters', + array(), + "[quote]\nThis is a long quote that is definitely going to exceed 80 characters\n[/quote]", + ), + array( + ' This is a short quote on its own line ', + array(), + '[quote]This is a short quote on its own line[/quote]', + ), + array( + "This is a short quote\non two lines", + array(), + "[quote]\nThis is a short quote\non two lines\n[/quote]", + ), + ); + } + + /** + * @dataProvider get_remove_bbcode_tests + */ + public function test_remove_bbcode($original, $name, $depth, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $parser = $container->get('text_formatter.parser'); + $utils = $container->get('text_formatter.utils'); + + $parsed = $parser->parse($original); + $actual = $utils->unparse($utils->remove_bbcode($parsed, $name, $depth)); + + $this->assertSame($expected, $actual); + } + + public function get_remove_bbcode_tests() + { + return array( + array( + 'Plain text', + 'b', + 1, + 'Plain text' + ), + array( + '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]', + 'quote', + 0, + '[b]bold[/b]', + ), + array( + '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]', + 'quote', + 1, + '[quote="u0"]q0[/quote][b]bold[/b]', + ), + array( + '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]', + 'quote', + 2, + '[quote="u0"][quote="u1"]q1[/quote]q0[/quote][b]bold[/b]', + ), + ); + } +} diff --git a/tests/text_processing/decode_message_test.php b/tests/text_processing/decode_message_test.php new file mode 100644 index 0000000000..7de599f2b1 --- /dev/null +++ b/tests/text_processing/decode_message_test.php @@ -0,0 +1,99 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; + +class phpbb_text_processing_decode_message_test extends phpbb_test_case +{ + /** + * @dataProvider get_legacy_tests + */ + public function test_legacy($original, $expected, $bbcode_uid = '') + { + $actual = $original; + decode_message($actual, $bbcode_uid); + + $this->assertSame($expected, $actual); + } + + public function get_legacy_tests() + { + return array( + array( + "&<>"'", + "&<>"'" + ), + array( + '<!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) -->', + ':)' + ), + array( + '<!-- w --><a class="postlink" href="http://www.phpbb.com">www.phpbb.com</a><!-- w -->', + 'www.phpbb.com' + ), + array( + '<!-- m --><a class="postlink" href="http://www.phpbb.com">http://www.phpbb.com</a><!-- m -->', + 'http://www.phpbb.com' + ), + /** + * Fails as per PHPBB3-8420 + * @link http://tracker.phpbb.com/browse/PHPBB3-8420 + * + array( + '[url=http://example.com:2cpxwbdy]<!-- s:arrow: --><img src="{SMILIES_PATH}/icon_arrow.gif" alt=":arrow:" title="Arrow" /><!-- s:arrow: --> here[/url:2cpxwbdy]', + '[url=http://example.com] :arrow: here[/url]', + '2cpxwbdy' + ), + */ + ); + } + + /** + * @dataProvider get_text_formatter_tests + */ + public function test_text_formatter($original, $expected) + { + $this->get_test_case_helpers()->set_s9e_services(); + + $actual = $original; + decode_message($actual); + + $this->assertSame($expected, $actual); + } + + public function get_text_formatter_tests() + { + return array( + array( + "<t>&<>\"'", + "&<>"'" + ), + array( + '<r><E>:)</E></r>', + ':)' + ), + array( + "<t>a<br/>\nb</t>", + "a\nb" + ), + /** + * @link http://tracker.phpbb.com/browse/PHPBB3-8420 + */ + array( + '<r><URL url="http://example.com"><s>[url=http://example.com]</s> <E>:arrow:</E> here<e>[/url]</e></URL></r>', + '[url=http://example.com] :arrow: here[/url]' + ), + ); + } +} diff --git a/tests/text_processing/fixtures/empty.xml b/tests/text_processing/fixtures/empty.xml new file mode 100644 index 0000000000..d8206ad124 --- /dev/null +++ b/tests/text_processing/fixtures/empty.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> +</dataset> diff --git a/tests/text_processing/fixtures/smilies.xml b/tests/text_processing/fixtures/smilies.xml new file mode 100644 index 0000000000..25b2e60836 --- /dev/null +++ b/tests/text_processing/fixtures/smilies.xml @@ -0,0 +1,443 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>1</value> + <value>:D</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>1</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>:-D</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>1</value> + </row> + <row> + <value>3</value> + <value>:grin:</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>3</value> + <value>1</value> + </row> + <row> + <value>4</value> + <value>:)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>4</value> + <value>1</value> + </row> + <row> + <value>5</value> + <value>:-)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>5</value> + <value>1</value> + </row> + <row> + <value>6</value> + <value>:smile:</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>6</value> + <value>1</value> + </row> + <row> + <value>7</value> + <value>;)</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>7</value> + <value>1</value> + </row> + <row> + <value>8</value> + <value>;-)</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>8</value> + <value>1</value> + </row> + <row> + <value>9</value> + <value>:wink:</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>9</value> + <value>1</value> + </row> + <row> + <value>10</value> + <value>:(</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>10</value> + <value>1</value> + </row> + <row> + <value>11</value> + <value>:-(</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>11</value> + <value>1</value> + </row> + <row> + <value>12</value> + <value>:sad:</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>12</value> + <value>1</value> + </row> + <row> + <value>13</value> + <value>:o</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>13</value> + <value>1</value> + </row> + <row> + <value>14</value> + <value>:-o</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>14</value> + <value>1</value> + </row> + <row> + <value>15</value> + <value>:eek:</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>15</value> + <value>1</value> + </row> + <row> + <value>16</value> + <value>:shock:</value> + <value>Shocked</value> + <value>icon_eek.gif</value> + <value>15</value> + <value>17</value> + <value>16</value> + <value>1</value> + </row> + <row> + <value>17</value> + <value>:?</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>17</value> + <value>1</value> + </row> + <row> + <value>18</value> + <value>:-?</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>18</value> + <value>1</value> + </row> + <row> + <value>19</value> + <value>:???:</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>19</value> + <value>1</value> + </row> + <row> + <value>20</value> + <value>8-)</value> + <value>Cool</value> + <value>icon_cool.gif</value> + <value>15</value> + <value>17</value> + <value>20</value> + <value>1</value> + </row> + <row> + <value>21</value> + <value>:cool:</value> + <value>Cool</value> + <value>icon_cool.gif</value> + <value>15</value> + <value>17</value> + <value>21</value> + <value>1</value> + </row> + <row> + <value>22</value> + <value>:lol:</value> + <value>Laughing</value> + <value>icon_lol.gif</value> + <value>15</value> + <value>17</value> + <value>22</value> + <value>1</value> + </row> + <row> + <value>23</value> + <value>:x</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>23</value> + <value>1</value> + </row> + <row> + <value>24</value> + <value>:-x</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>24</value> + <value>1</value> + </row> + <row> + <value>25</value> + <value>:mad:</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>25</value> + <value>1</value> + </row> + <row> + <value>26</value> + <value>:P</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>26</value> + <value>1</value> + </row> + <row> + <value>27</value> + <value>:-P</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>27</value> + <value>1</value> + </row> + <row> + <value>28</value> + <value>:razz:</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>28</value> + <value>1</value> + </row> + <row> + <value>29</value> + <value>:oops:</value> + <value>Embarrassed</value> + <value>icon_redface.gif</value> + <value>15</value> + <value>17</value> + <value>29</value> + <value>1</value> + </row> + <row> + <value>30</value> + <value>:cry:</value> + <value>Crying or Very Sad</value> + <value>icon_cry.gif</value> + <value>15</value> + <value>17</value> + <value>30</value> + <value>1</value> + </row> + <row> + <value>31</value> + <value>:evil:</value> + <value>Evil or Very Mad</value> + <value>icon_evil.gif</value> + <value>15</value> + <value>17</value> + <value>31</value> + <value>1</value> + </row> + <row> + <value>32</value> + <value>:twisted:</value> + <value>Twisted Evil</value> + <value>icon_twisted.gif</value> + <value>15</value> + <value>17</value> + <value>32</value> + <value>1</value> + </row> + <row> + <value>33</value> + <value>:roll:</value> + <value>Rolling Eyes</value> + <value>icon_rolleyes.gif</value> + <value>15</value> + <value>17</value> + <value>33</value> + <value>1</value> + </row> + <row> + <value>34</value> + <value>:!:</value> + <value>Exclamation</value> + <value>icon_exclaim.gif</value> + <value>15</value> + <value>17</value> + <value>34</value> + <value>1</value> + </row> + <row> + <value>35</value> + <value>:?:</value> + <value>Question</value> + <value>icon_question.gif</value> + <value>15</value> + <value>17</value> + <value>35</value> + <value>1</value> + </row> + <row> + <value>36</value> + <value>:idea:</value> + <value>Idea</value> + <value>icon_idea.gif</value> + <value>15</value> + <value>17</value> + <value>36</value> + <value>1</value> + </row> + <row> + <value>37</value> + <value>:arrow:</value> + <value>Arrow</value> + <value>icon_arrow.gif</value> + <value>15</value> + <value>17</value> + <value>37</value> + <value>1</value> + </row> + <row> + <value>38</value> + <value>:|</value> + <value>Neutral</value> + <value>icon_neutral.gif</value> + <value>15</value> + <value>17</value> + <value>38</value> + <value>1</value> + </row> + <row> + <value>39</value> + <value>:-|</value> + <value>Neutral</value> + <value>icon_neutral.gif</value> + <value>15</value> + <value>17</value> + <value>39</value> + <value>1</value> + </row> + <row> + <value>40</value> + <value>:mrgreen:</value> + <value>Mr. Green</value> + <value>icon_mrgreen.gif</value> + <value>15</value> + <value>17</value> + <value>40</value> + <value>1</value> + </row> + <row> + <value>41</value> + <value>:geek:</value> + <value>Geek</value> + <value>icon_e_geek.gif</value> + <value>17</value> + <value>17</value> + <value>41</value> + <value>1</value> + </row> + <row> + <value>42</value> + <value>:ugeek:</value> + <value>Uber Geek</value> + <value>icon_e_ugeek.gif</value> + <value>17</value> + <value>18</value> + <value>42</value> + <value>1</value> + </row> + <row> + <value>43</value> + <value>8)</value> + <value>8)</value> + <value>custom.gif</value> + <value>17</value> + <value>18</value> + <value>42</value> + <value>1</value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/generate_text_for_display_test.php b/tests/text_processing/generate_text_for_display_test.php index 057416da33..dba3713447 100644 --- a/tests/text_processing/generate_text_for_display_test.php +++ b/tests/text_processing/generate_text_for_display_test.php @@ -11,10 +11,8 @@ * */ -require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; -require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; -require_once dirname(__FILE__) . '/../mock/user.php'; -require_once dirname(__FILE__) . '/../mock/cache.php'; +require_once __DIR__ . '/../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../phpBB/includes/functions_content.php'; class phpbb_text_processing_generate_text_for_display_test extends phpbb_test_case { @@ -24,21 +22,195 @@ class phpbb_text_processing_generate_text_for_display_test extends phpbb_test_ca parent::setUp(); + $phpbb_dispatcher = new phpbb_mock_event_dispatcher; + $config = new \phpbb\config\config(array()); + set_config(null, null, null, $config); + } + + /** + * @dataProvider get_legacy_tests + */ + public function test_legacy($original, $expected, $uid = '', $bitfield = '', $flags = 0, $censor_text = true) + { + global $cache, $user; + + global $phpbb_root_path, $phpEx; + $cache = new phpbb_mock_cache; + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewcensors', true); + $user->optionset('viewflash', true); + $user->optionset('viewimg', true); + $user->optionset('viewsmilies', true); + + $actual = generate_text_for_display($original, $uid, $bitfield, $flags, $censor_text); + + $this->assertSame($expected, $actual); + } - $user = new phpbb_mock_user; + public function get_legacy_tests() + { + return array( + array( + '', + '' + ), + array( + '0', + '0' + ), + ); + } + + public function test_censor_is_restored() + { + global $phpbb_container; + + $phpbb_container = new phpbb_mock_container_builder; + + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); $user->optionset('viewcensors', false); - $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); + $config = new \phpbb\config\config(array('allow_nocensors' => true)); + + $auth = $this->getMock('phpbb\\auth\\auth'); + $auth->expects($this->any()) + ->method('acl_get') + ->with('u_chgcensors') + ->will($this->returnValue(true)); + + $phpbb_container->set('user', $user); + $phpbb_container->set('config', $config); + $phpbb_container->set('auth', $auth); + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container); + $renderer = $phpbb_container->get('text_formatter.renderer'); + + $original = '<r><CENSOR with="banana">apple</CENSOR></r>'; + + $renderer->set_viewcensors(false); + $this->assertSame('apple', $renderer->render($original)); + $renderer->set_viewcensors(true); + $this->assertSame('banana', $renderer->render($original)); + $this->assertSame('apple', generate_text_for_display($original, '', '', 0, false)); + $this->assertSame('banana', $renderer->render($original), 'The original setting was not restored'); + + $renderer->set_viewcensors(false); + $this->assertSame('apple', $renderer->render($original)); + $this->assertSame('banana', generate_text_for_display($original, '', '', 0, truee)); + $this->assertSame('apple', $renderer->render($original), 'The original setting was not restored'); } - public function test_empty_string() + /** + * @dataProvider get_text_formatter_tests + */ + public function test_text_formatter($original, $expected, $censor_text = true, $setup = null) { - $this->assertSame('', generate_text_for_display('', '', '', 0)); + global $phpbb_container; + + $phpbb_container = new phpbb_mock_container_builder; + + if (isset($setup)) + { + $setup($phpbb_container, $this); + } + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container); + + $this->assertSame($expected, generate_text_for_display($original, '', '', 0, $censor_text)); } - public function test_zero_string() + public function get_text_formatter_tests() { - $this->assertSame('0', generate_text_for_display('0', '', '', 0)); + return array( + array( + '<t>Plain text</t>', + 'Plain text' + ), + array( + '<r>Hello <URL url="http://example.org"><s>[url=http://example.org]</s>world<e>[/url]</e></URL></r>', + 'Hello <a href="http://example.org" class="postlink">world</a>' + ), + array( + '<t>&<>"\'</t>', + '&<>"\'' + ), + array( + '<r><CENSOR with="banana">apple</CENSOR></r>', + 'banana', + true + ), + array( + '<r><CENSOR with="banana">apple</CENSOR></r>', + 'apple', + false + ), + array( + '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>', + '<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="123" height="456"><param name="movie" value="http://localhost/foo.swf"><param name="play" value="false"><param name="loop" value="false"><param name="quality" value="high"><param name="allowScriptAccess" value="never"><param name="allowNetworking" value="internal"><embed src="http://localhost/foo.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="123" height="456" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></object>' + ), + array( + '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>', + 'http://localhost/foo.swf', + true, + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewflash', false); + + $phpbb_container->set('user', $user); + } + ), + array( + '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>', + '<img src="http://localhost/mrgreen.gif" class="postimage" alt="Image">' + ), + array( + '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>', + '<a href="http://localhost/mrgreen.gif" class="postlink">http://localhost/mrgreen.gif</a>', + true, + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewimg', false); + + $phpbb_container->set('user', $user); + } + ), + array( + '<r><E>:)</E></r>', + '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" alt=":)" title="Smile">' + ), + array( + '<r><E>:)</E></r>', + ':)', + true, + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('smilies', false); + + $phpbb_container->set('user', $user); + } + ), + ); } } diff --git a/tests/text_processing/generate_text_for_edit_test.php b/tests/text_processing/generate_text_for_edit_test.php new file mode 100644 index 0000000000..105e8da86b --- /dev/null +++ b/tests/text_processing/generate_text_for_edit_test.php @@ -0,0 +1,92 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once __DIR__ . '/../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../phpBB/includes/functions_content.php'; + +class phpbb_text_processing_generate_text_for_edit_test extends phpbb_test_case +{ + /** + * @dataProvider get_legacy_tests + */ + public function test_legacy($original, $expected, $uid = '', $flags = 0) + { + global $cache, $user, $phpbb_dispatcher; + + $cache = new phpbb_mock_cache; + $phpbb_dispatcher = new phpbb_mock_event_dispatcher; + + $user = new phpbb_mock_user; + $user->optionset('viewcensors', false); + + $return = generate_text_for_edit($original, $uid, $flags); + + $this->assertSame($expected, $return['text']); + } + + public function get_legacy_tests() + { + return array( + array( + '', + '' + ), + array( + '0', + '0' + ), + array( + 'Hello [url=http://example.org:1f4coh9x]world[/url:1f4coh9x] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) -->', + 'Hello [url=http://example.org]world[/url] :)', + '1f4coh9x', + 0 + ), + array( + "&<>"'", + "&<>"'" + ) + ); + } + + /** + * @dataProvider get_text_formatter_tests + */ + public function test_text_formatter($original, $expected) + { + global $phpbb_dispatcher; + $phpbb_dispatcher = new phpbb_mock_event_dispatcher; + $this->get_test_case_helpers()->set_s9e_services(); + + $return = generate_text_for_edit($original, '', 0); + + $this->assertSame($expected, $return['text']); + } + + public function get_text_formatter_tests() + { + return array( + array( + '<t>Plain text</t>', + 'Plain text' + ), + array( + '<r>Hello <URL url="http://example.org"><s>[url=http://example.org]</s>world<e>[/url]</e></URL> <E>:)</E></r>', + 'Hello [url=http://example.org]world[/url] :)' + ), + array( + '<t>&<>"\'</t>', + "&<>"'" + ) + ); + } +} diff --git a/tests/text_processing/generate_text_for_storage_test.php b/tests/text_processing/generate_text_for_storage_test.php new file mode 100644 index 0000000000..474f6d8f0f --- /dev/null +++ b/tests/text_processing/generate_text_for_storage_test.php @@ -0,0 +1,183 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once __DIR__ . '/../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../phpBB/includes/functions_compatibility.php'; +require_once __DIR__ . '/../../phpBB/includes/functions_content.php'; +require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php'; + +class phpbb_text_processing_generate_text_for_storage_test extends phpbb_test_case +{ + public function setUp() + { + global $config, $phpbb_container, $phpbb_dispatcher; + + parent::setUp(); + + $config = new \phpbb\config\config(array()); + set_config(null, null, null, $config); + + $phpbb_container = new phpbb_mock_container_builder; + $phpbb_container->set('config', $config); + $this->get_test_case_helpers()->set_s9e_services($phpbb_container); + + $phpbb_dispatcher = new phpbb_mock_event_dispatcher; + } + + /** + * @dataProvider get_text_formatter_tests + */ + public function test_text_formatter($original, $expected, $allow_bbcode, $allow_urls, $allow_smilies, $allow_img_bbcode, $allow_flash_bbcode, $allow_quote_bbcode, $allow_url_bbcode, $setup = null) + { + $actual = $original; + $uid = ''; + $bitfield = ''; + $flags = 0; + + if (isset($setup)) + { + $setup(); + } + + generate_text_for_storage($actual, $uid, $bitfield, $flags, $allow_bbcode, $allow_urls, $allow_smilies, $allow_img_bbcode, $allow_flash_bbcode, $allow_quote_bbcode, $allow_url_bbcode); + + $this->assertSame($expected, $actual); + } + + public function get_text_formatter_tests() + { + return array( + array( + 'Hello world', + '<t>Hello world</t>', + true, + true, + true, + true, + true, + true, + true, + ), + array( + 'Hello [url=http://example.org]world[/url] :)', + '<r>Hello <URL url="http://example.org"><s>[url=http://example.org]</s>world<e>[/url]</e></URL> <E>:)</E></r>', + true, + true, + true, + true, + true, + true, + true, + ), + array( + '&<>"\'', + '<t>&<>"\'</t>', + true, + true, + true, + true, + true, + true, + true, + ), + array( + '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]', + '<t>[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]</t>', + false, + false, + false, + false, + false, + false, + false, + ), + array( + '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]', + '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]</r>', + true, + false, + false, + false, + false, + false, + false, + ), + array( + '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]', + '<r>[b]..[/b] <URL url="http://example.org">http://example.org</URL> :) [img]<URL url="http://example.org/img.png">http://example.org/img.png</URL>[/img] [flash=123,123]<URL url="http://example.org/flash.swf">http://example.org/flash.swf</URL>[/flash] [quote]...[/quote] [url]<URL url="http://example.org">http://example.org</URL>[/url]</r>', + false, + true, + false, + false, + false, + false, + true, + ), + array( + '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]', + '<r>[b]..[/b] http://example.org <E>:)</E> [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]</r>', + false, + false, + true, + false, + false, + false, + false, + ), + array( + '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]', + '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) <IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG> [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]</r>', + true, + false, + false, + true, + false, + false, + false, + ), + array( + '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]', + '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) [img]http://example.org/img.png[/img] <FLASH height="123" url="http://example.org/flash.swf" width="123"><s>[flash=123,123]</s>http://example.org/flash.swf<e>[/flash]</e></FLASH> [quote]...[/quote] [url]http://example.org[/url]</r>', + true, + false, + false, + false, + true, + false, + false, + ), + array( + '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]', + '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] <QUOTE><s>[quote]</s>...<e>[/quote]</e></QUOTE> [url]http://example.org[/url]</r>', + true, + false, + false, + false, + false, + true, + false, + ), + array( + '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]', + '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] <URL url="http://example.org"><s>[url]</s>http://example.org<e>[/url]</e></URL></r>', + true, + false, + false, + false, + false, + false, + true, + ), + ); + } +} diff --git a/tests/text_processing/message_parser_test.php b/tests/text_processing/message_parser_test.php new file mode 100644 index 0000000000..bee1b3fca3 --- /dev/null +++ b/tests/text_processing/message_parser_test.php @@ -0,0 +1,543 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once __DIR__ . '/../../phpBB/includes/bbcode.php'; +require_once __DIR__ . '/../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../phpBB/includes/functions_content.php'; +require_once __DIR__ . '/../../phpBB/includes/message_parser.php'; +require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php'; + +class phpbb_text_processing_message_parser_test extends phpbb_test_case +{ + public static function setUpBeforeClass() + { + parent::setUpBeforeClass(); + + // Set up an intercepting proxy for getimagesize() calls + stream_wrapper_unregister('http'); + stream_wrapper_register('http', __CLASS__ . '_proxy'); + } + + public static function tearDownAfterClass() + { + parent::tearDownAfterClass(); + stream_wrapper_restore('http'); + } + + protected function prepare_s9e_services($setup = null) + { + global $config, $phpbb_container, $user; + + $config = new \phpbb\config\config(array('max_poll_options' => 999)); + + $map = array( + array('MAX_FLASH_HEIGHT_EXCEEDED', 123, 'Your flash files may only be up to 123 pixels high.'), + array('MAX_FLASH_WIDTH_EXCEEDED', 456, 'Your flash files may only be up to 456 pixels wide.'), + array('MAX_FONT_SIZE_EXCEEDED', 120, 'You may only use fonts up to size 120.'), + array('MAX_FONT_SIZE_EXCEEDED', 200, 'You may only use fonts up to size 200.'), + array('MAX_IMG_HEIGHT_EXCEEDED', 12, 'Your images may only be up to 12 pixels high.'), + array('MAX_IMG_WIDTH_EXCEEDED', 34, 'Your images may only be up to 34 pixels wide.'), + array('TOO_MANY_SMILIES', 3, 'Your message contains too many smilies. The maximum number of smilies allowed is 3.'), + array('TOO_MANY_URLS', 2, 'Your message contains too many URLs. The maximum number of URLs allowed is 2.'), + array('UNAUTHORISED_BBCODE', '[flash]', 'You cannot use certain BBCodes: [flash].'), + array('UNAUTHORISED_BBCODE', '[img]', 'You cannot use certain BBCodes: [img].'), + array('UNAUTHORISED_BBCODE', '[quote]', 'You cannot use certain BBCodes: [quote].'), + array('UNAUTHORISED_BBCODE', '[url]', 'You cannot use certain BBCodes: [url].'), + array('UNABLE_GET_IMAGE_SIZE', 'It was not possible to determine the dimensions of the image.'), + ); + + $user = $this->getMockBuilder('phpbb\\user')->disableOriginalConstructor()->getMock(); + $user->expects($this->any()) + ->method('lang') + ->will($this->returnValueMap($map)); + + $user->data = array( + 'is_bot' => false, + 'is_registered' => true, + 'user_id' => 2, + ); + $user->style = array('style_id' => 1); + + $user->lang = array( + 'NO_POLL_TITLE' => 'You have to enter a poll title.', + 'POLL_TITLE_TOO_LONG' => 'The poll title must contain fewer than 100 characters.', + 'POLL_TITLE_COMP_TOO_LONG' => 'The parsed size of your poll title is too large, consider removing BBCodes or smilies.', + 'TOO_FEW_POLL_OPTIONS' => 'You must enter at least two poll options.', + 'TOO_MANY_POLL_OPTIONS' => 'You have tried to enter too many poll options.', + 'TOO_MANY_USER_OPTIONS' => 'You cannot specify more options per user than existing poll options.', + ); + + $phpbb_container = new phpbb_mock_container_builder; + $phpbb_container->set('user', $user); + $phpbb_container->set('config', $config); + + if (isset($setup)) + { + $setup($phpbb_container, $this); + } + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container); + } + + /** + * @dataProvider get_test_polls + */ + public function test_parse_poll($poll, $expected, $warn_msg = array()) + { + $this->prepare_s9e_services(); + + $message_parser = new parse_message('Me[i]s[/i]sage'); + + // Add some default values + $poll += array( + 'poll_length' => 123, + 'poll_start' => 123, + 'poll_last_vote' => 123, + 'poll_vote_change' => true, + 'enable_bbcode' => true, + 'enable_urls' => true, + 'enable_smilies' => true, + 'img_status' => true + ); + + $message_parser->parse_poll($poll); + $this->assertSame($expected, array_intersect_key($poll, $expected)); + + $this->assertSame( + '<r>Me<I><s>[i]</s>s<e>[/i]</e></I>sage</r>', + $message_parser->parse(true, true, true, true, true, true, true, false) + ); + + $this->assertSame($warn_msg, $message_parser->warn_msg); + } + + public function get_test_polls() + { + return array( + array( + array( + 'poll_title' => 'foo [b]bar[/b] baz', + 'poll_option_text' => "[i]foo[/i]\nbar\n[i]baz[/i]", + 'poll_max_options' => 3, + 'poll_options_size' => 3 + ), + array( + 'poll_title' => '<r>foo <B><s>[b]</s>bar<e>[/b]</e></B> baz</r>', + 'poll_option_text' => "<r><I><s>[i]</s>foo<e>[/i]</e></I></r>\n<t>bar</t>\n<r><I><s>[i]</s>baz<e>[/i]</e></I></r>", + 'poll_options' => array( + '<r><I><s>[i]</s>foo<e>[/i]</e></I></r>', + '<t>bar</t>', + '<r><I><s>[i]</s>baz<e>[/i]</e></I></r>' + ) + ) + ), + array( + array( + 'poll_title' => 'xxx', + 'poll_option_text' => "[quote]quote[/quote]\n:)", + 'poll_max_options' => 2, + 'poll_options_size' => 2 + ), + array( + 'poll_title' => '<t>xxx</t>', + 'poll_option_text' => "<t>[quote]quote[/quote]</t>\n<r><E>:)</E></r>", + 'poll_options' => array( + '<t>[quote]quote[/quote]</t>', + '<r><E>:)</E></r>' + ) + ), + array('You cannot use certain BBCodes: [quote].') + ), + array( + array( + 'poll_title' => 'xxx', + 'poll_option_text' => "[flash=12,34]http://example.org/x.swf[/flash]\n:)", + 'poll_max_options' => 2, + 'poll_options_size' => 2 + ), + array( + 'poll_title' => '<t>xxx</t>', + 'poll_option_text' => "<t>[flash=12,34]http://example.org/x.swf[/flash]</t>\n<r><E>:)</E></r>", + 'poll_options' => array( + '<t>[flash=12,34]http://example.org/x.swf[/flash]</t>', + '<r><E>:)</E></r>' + ) + ), + array('You cannot use certain BBCodes: [flash].') + ), + array( + array( + 'poll_title' => 'xxx', + 'poll_option_text' => "[b]x\ny[/b]", + 'poll_max_options' => 2, + 'poll_options_size' => 2 + ), + array( + 'poll_title' => '<t>xxx</t>', + 'poll_option_text' => "<r><B><s>[b]</s>x</B></r>\n<t>y[/b]</t>", + 'poll_options' => array( + '<r><B><s>[b]</s>x</B></r>', + '<t>y[/b]</t>', + ) + ) + ), + ); + } + + /** + * @dataProvider get_test_cases + */ + public function test_options($original, $expected, array $args, $setup = null, $warn_msg = array()) + { + $this->prepare_s9e_services($setup); + + $message_parser = new parse_message($original); + call_user_func_array(array($message_parser, 'parse'), $args); + + $this->assertSame($expected, $message_parser->message); + $this->assertSame($warn_msg, $message_parser->warn_msg); + } + + public function get_test_cases() + { + return array( + array( + '[b]bold[/b]', + '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>', + array(true, true, true, true, true, true, true) + ), + array( + '[b]bold[/b]', + '<t>[b]bold[/b]</t>', + array(false, true, true, true, true, true, true) + ), + array( + 'http://example.org', + '<r><URL url="http://example.org">http://example.org</URL></r>', + array(true, true, true, true, true, true, true) + ), + array( + 'http://example.org', + '<t>http://example.org</t>', + array(true, false, true, true, true, true, true) + ), + array( + ':)', + '<r><E>:)</E></r>', + array(true, true, true, true, true, true, true) + ), + array( + ':)', + '<t>:)</t>', + array(true, true, false, true, true, true, true) + ), + array( + '[url=http://example.org][img]http://example.org/img.png[/img][/url]', + '<r><URL url="http://example.org"><s>[url=http://example.org]</s><IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG><e>[/url]</e></URL></r>', + array(true, true, true, true, true, true, true) + ), + array( + '[url=http://example.org][img]http://example.org/img.png[/img][/url]', + '<r><URL url="http://example.org"><s>[url=http://example.org]</s>[img]http://example.org/img.png[/img]<e>[/url]</e></URL></r>', + array(true, true, true, false, true, true, true), + null, + array('You cannot use certain BBCodes: [img].') + ), + array( + '[flash=12,34]http://example.org/foo.swf[/flash]', + '<r><FLASH height="34" url="http://example.org/foo.swf" width="12"><s>[flash=12,34]</s><URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL><e>[/flash]</e></FLASH></r>', + array(true, true, true, true, true, true, true) + ), + array( + '[flash=12,34]http://example.org/foo.swf[/flash]', + '<r>[flash=12,34]<URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL>[/flash]</r>', + array(true, true, true, true, false, true, true), + null, + array('You cannot use certain BBCodes: [flash].') + ), + array( + '[quote="foo"]bar :)[/quote]', + '<r><QUOTE author="foo"><s>[quote="foo"]</s>bar <E>:)</E><e>[/quote]</e></QUOTE></r>', + array(true, true, true, true, true, true, true) + ), + array( + '[quote="foo"]bar :)[/quote]', + '<r>[quote="foo"]bar <E>:)</E>[/quote]</r>', + array(true, true, true, true, true, false, true), + null, + array('You cannot use certain BBCodes: [quote].') + ), + array( + '[url=http://example.org][img]http://example.org/img.png[/img][/url]', + '<r><URL url="http://example.org"><s>[url=http://example.org]</s><IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG><e>[/url]</e></URL></r>', + array(true, true, true, true, true, true, true) + ), + array( + '[url=http://example.org][img]http://example.org/img.png[/img][/url]', + '<r>[url=http://example.org]<IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG>[/url]</r>', + array(true, true, true, true, true, true, false), + null, + array('You cannot use certain BBCodes: [url].') + ), + array( + '[size=200]200[/size]', + '<r><SIZE size="200"><s>[size=200]</s>200<e>[/size]</e></SIZE></r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_font_size', 200); + } + ), + array( + '[size=200]200[/size]', + '<r><SIZE size="200"><s>[size=200]</s>200<e>[/size]</e></SIZE></r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_font_size', 0); + } + ), + array( + '[size=2000]2000[/size]', + '<t>[size=2000]2000[/size]</t>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_font_size', 200); + }, + array('You may only use fonts up to size 200.') + ), + array( + '[size=0]0[/size]', + '<t>[size=0]0[/size]</t>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_font_size', 200); + } + ), + array( + '[size=200]200[/size]', + '<r><SIZE size="200"><s>[size=200]</s>200<e>[/size]</e></SIZE></r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_sig_font_size', 200); + } + ), + array( + '[size=200]200[/size]', + '<t>[size=200]200[/size]</t>', + array(true, true, true, true, true, true, true, true, 'sig'), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_sig_font_size', 120); + }, + array('You may only use fonts up to size 120.') + ), + array( + '[img]http://example.org/100x100.png[/img]', + '<r>[img]<URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL>[/img]</r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_img_height', 12); + }, + array('Your images may only be up to 12 pixels high.') + ), + array( + '[img]http://example.org/100x100.png[/img]', + '<r>[img]<URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL>[/img]</r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_img_width', 34); + }, + array('Your images may only be up to 34 pixels wide.') + ), + array( + '[img]http://example.org/100x100.png[/img]', + '<r><IMG src="http://example.org/100x100.png"><s>[img]</s><URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL><e>[/img]</e></IMG></r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_img_height', 0); + $phpbb_container->get('config')->set('max_post_img_width', 0); + } + ), + array( + '[img]http://example.org/100x100.png[/img]', + '<r><IMG src="http://example.org/100x100.png"><s>[img]</s><URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL><e>[/img]</e></IMG></r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_img_height', 100); + $phpbb_container->get('config')->set('max_post_img_width', 100); + } + ), + array( + '[img]http://example.org/100x100.png[/img]', + '<r><IMG src="http://example.org/100x100.png"><s>[img]</s><URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL><e>[/img]</e></IMG></r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_sig_img_height', 12); + $phpbb_container->get('config')->set('max_sig_img_width', 34); + } + ), + array( + '[img]http://example.org/404.png[/img]', + '<r>[img]<URL url="http://example.org/404.png">http://example.org/404.png</URL>[/img]</r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_img_height', 12); + }, + array('It was not possible to determine the dimensions of the image.') + ), + array( + '[flash=999,999]http://example.org/foo.swf[/flash]', + '<r>[flash=999,999]<URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL>[/flash]</r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_img_height', 123); + }, + array('Your flash files may only be up to 123 pixels high.') + ), + array( + '[flash=999,999]http://example.org/foo.swf[/flash]', + '<r>[flash=999,999]<URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL>[/flash]</r>', + array(true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_img_width', 456); + }, + array('Your flash files may only be up to 456 pixels wide.') + ), + array( + ':) :) :)', + '<r><E>:)</E> <E>:)</E> <E>:)</E></r>', + array(true, true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_smilies', 3); + } + ), + array( + ':) :) :) :)', + '<r><E>:)</E> <E>:)</E> <E>:)</E> :)</r>', + array(true, true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_smilies', 3); + }, + array('Your message contains too many smilies. The maximum number of smilies allowed is 3.') + ), + array( + ':) :) :) :)', + '<r><E>:)</E> <E>:)</E> <E>:)</E> <E>:)</E></r>', + array(true, true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_smilies', 0); + } + ), + array( + ':) :) :) :)', + '<r><E>:)</E> <E>:)</E> <E>:)</E> <E>:)</E></r>', + array(true, true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_sig_smilies', 3); + } + ), + array( + ':) :) :) :)', + '<r><E>:)</E> <E>:)</E> <E>:)</E> :)</r>', + array(true, true, true, true, true, true, true, true, 'sig'), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_sig_smilies', 3); + }, + array('Your message contains too many smilies. The maximum number of smilies allowed is 3.') + ), + array( + 'http://example.org http://example.org http://example.org', + '<r><URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL> http://example.org</r>', + array(true, true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_urls', 2); + }, + array('Your message contains too many URLs. The maximum number of URLs allowed is 2.') + ), + array( + 'http://example.org http://example.org http://example.org', + '<r><URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL></r>', + array(true, true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_post_urls', 0); + } + ), + array( + 'http://example.org http://example.org http://example.org', + '<r><URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL></r>', + array(true, true, true, true, true, true, true, true), + function ($phpbb_container) + { + $phpbb_container->get('config')->set('max_sig_urls', 2); + } + ), + ); + } +} + +class phpbb_text_processing_message_parser_test_proxy +{ + protected $response; + + public function stream_open($url) + { + if (strpos($url, '100x100')) + { + // Return a 100 x 100 PNG image + $this->response = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQAAAABYmaj5AAAAE0lEQVR4AWOgKxgFo2AUjIJRAAAFeAABHs0ozQAAAABJRU5ErkJggg=='); + } + else + { + $this->response = '404 not found'; + } + + return true; + } + + public function stream_stat() + { + return false; + } + + public function stream_read($len) + { + $chunk = substr($this->response, 0, $len); + $this->response = substr($this->response, $len); + + return $chunk; + } + + public function stream_eof() + { + return ($this->response === false); + } +} diff --git a/tests/text_processing/smilies_test.php b/tests/text_processing/smilies_test.php new file mode 100644 index 0000000000..3bbe065d36 --- /dev/null +++ b/tests/text_processing/smilies_test.php @@ -0,0 +1,52 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once __DIR__ . '/../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../phpBB/includes/functions_content.php'; + +class phpbb_text_processing_smilies_test extends phpbb_test_case +{ + /** + * @dataProvider get_text_formatter_tests + */ + public function test_text_formatter($original, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(null, __DIR__ . '/fixtures/smilies.xml'); + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + $this->assertSame($expected, $renderer->render($parser->parse($original))); + } + + public function get_text_formatter_tests() + { + return array( + array( + ':) beginning', + '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" alt=":)" title="Smile"> beginning' + ), + array( + 'end :)', + 'end <img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" alt=":)" title="Smile">' + ), + array( + ':)', + '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" alt=":)" title="Smile">' + ), + array( + 'xx (18) 8) xx', + 'xx (18) <img class="smilies" src="phpBB/images/smilies/custom.gif" alt="8)" title="8)"> xx' + ), + ); + } +} diff --git a/tests/text_processing/strip_bbcode_test.php b/tests/text_processing/strip_bbcode_test.php new file mode 100644 index 0000000000..827d8d4a52 --- /dev/null +++ b/tests/text_processing/strip_bbcode_test.php @@ -0,0 +1,42 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; + +class phpbb_text_processing_strip_bbcode_test extends phpbb_test_case +{ + public function test_legacy() + { + $original = '[b:20m4ill1]bold[/b:20m4ill1]'; + $expected = ' bold '; + + $actual = $original; + strip_bbcode($actual); + + $this->assertSame($expected, $actual, '20m4ill1'); + } + + public function test_s9e() + { + $phpbb_container = $this->get_test_case_helpers()->set_s9e_services(); + + $original = '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>'; + $expected = ' bold '; + + $actual = $original; + strip_bbcode($actual); + + $this->assertSame($expected, $actual); + } +} diff --git a/tests/text_processing/tickets_data/PHPBB3-10002.html b/tests/text_processing/tickets_data/PHPBB3-10002.html new file mode 100644 index 0000000000..82990b2253 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10002.html @@ -0,0 +1,2 @@ +<blockquote class="uncited"><div><ul><li>one +<blockquote class="uncited"><div><ul><li>two</li></ul></div></blockquote></li></ul></div></blockquote>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10002.txt b/tests/text_processing/tickets_data/PHPBB3-10002.txt new file mode 100644 index 0000000000..fe2f29073f --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10002.txt @@ -0,0 +1,2 @@ +[quote][list][*]one +[quote][list][*]two[/list][/quote]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10122.html b/tests/text_processing/tickets_data/PHPBB3-10122.html new file mode 100644 index 0000000000..f0fb6115b2 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10122.html @@ -0,0 +1 @@ +<ul style="list-style-type: none"><li>This is my indented text</li></ul>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10122.txt b/tests/text_processing/tickets_data/PHPBB3-10122.txt new file mode 100644 index 0000000000..a5e059df66 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10122.txt @@ -0,0 +1 @@ +[list=none][*]This is my indented text[/list]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10268.html b/tests/text_processing/tickets_data/PHPBB3-10268.html new file mode 100644 index 0000000000..c89e63f9a3 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10268.html @@ -0,0 +1,4 @@ +<blockquote><div><cite><a href="http://phpbb.com" class="postlink">http://phpbb.com</a> wrote:</cite>...</div></blockquote> +<blockquote><div><cite><a href="http://phpbb.com" class="postlink"> http://phpbb.com</a> wrote:</cite>...</div></blockquote> +<span style="font-weight: bold"><a href="http://phpbb.com" class="postlink">http://phpbb.com</a></span><br> +<span style="font-weight: bold"> <a href="http://phpbb.com" class="postlink">http://phpbb.com</a></span><br> diff --git a/tests/text_processing/tickets_data/PHPBB3-10268.txt b/tests/text_processing/tickets_data/PHPBB3-10268.txt new file mode 100644 index 0000000000..b4e49c9454 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10268.txt @@ -0,0 +1,4 @@ +[quote="http://phpbb.com"]...[/quote] +[quote=" http://phpbb.com"]...[/quote] +[b]http://phpbb.com[/b] +[b] http://phpbb.com[/b] diff --git a/tests/text_processing/tickets_data/PHPBB3-10425.html b/tests/text_processing/tickets_data/PHPBB3-10425.html new file mode 100644 index 0000000000..522b2f8858 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10425.html @@ -0,0 +1,3 @@ +<a href="http://ar.wikipedia.org/wiki/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" class="postlink">http://ar.wikipedia.org/wiki/الصفحة_الرئيسية</a><br> +<a href="http://ar.wikipedia.org/wiki/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" class="postlink">http://ar.wikipedia.org/wiki/الصفحة_الرئيسية</a><br> +<a href="http://ar.wikipedia.org/wiki/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" class="postlink">link</a>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10425.txt b/tests/text_processing/tickets_data/PHPBB3-10425.txt new file mode 100644 index 0000000000..d93c0446b6 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10425.txt @@ -0,0 +1,3 @@ +http://ar.wikipedia.org/wiki/الصفحة_الرئيسية +[url]http://ar.wikipedia.org/wiki/الصفحة_الرئيسية[/url] +[url=http://ar.wikipedia.org/wiki/الصفحة_الرئيسية]link[/url]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10587.html b/tests/text_processing/tickets_data/PHPBB3-10587.html new file mode 100644 index 0000000000..4c2e536989 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10587.html @@ -0,0 +1,2 @@ +<a href="http://example.org/?tourney%5Bid%5D=34&action=brackets" class="postlink">http://example.org/?tourney[id]=34&action=brackets</a><br> +<a href="http://example.org/?tourney%5Bid%5D=34&action=brackets" class="postlink">link</a>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10587.txt b/tests/text_processing/tickets_data/PHPBB3-10587.txt new file mode 100644 index 0000000000..84788b720d --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10587.txt @@ -0,0 +1,2 @@ +[url]http://example.org/?tourney[id]=34&action=brackets[/url] +[url="http://example.org/?tourney[id]=34&action=brackets"]link[/url]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10922.html b/tests/text_processing/tickets_data/PHPBB3-10922.html new file mode 100644 index 0000000000..3ff117f171 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10922.html @@ -0,0 +1,9 @@ +<a href="mailto:user@example.org">user@example.org</a><br> +<a href="mailto:user@example.org">...</a><br> +<a href="mailto:user@example.org">...</a><br> +<a href="mailto:user@example.org?subject=Hello">...</a><br> +<a href="mailto:user@example.org?subject=Hi%20there">user@example.org</a><br> +<a href="mailto:user@example.org?body=Hi%20there">user@example.org</a><br> +<a href="mailto:user@example.org?subject=Hello&body=Sent%20from%20phpBB">user@example.org</a><br> +<a href="mailto:user@example.org?subject=Hello&body=Sent%20from%20phpBB">user@example.org</a><br> +<a href="mailto:user@example.org?subject=Hello&body=Sent%20from%20phpBB">...</a><br> diff --git a/tests/text_processing/tickets_data/PHPBB3-10922.txt b/tests/text_processing/tickets_data/PHPBB3-10922.txt new file mode 100644 index 0000000000..e533ce6ed5 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10922.txt @@ -0,0 +1,9 @@ +[email]user@example.org[/email] +[email=user@example.org]...[/email] +[email=user@example.org ]...[/email] +[email=user@example.org subject="Hello"]...[/email] +[email subject="Hi there"]user@example.org[/email] +[email body="Hi there"]user@example.org[/email] +[email subject="Hello" body="Sent from phpBB"]user@example.org[/email] +[email body="Sent from phpBB" subject="Hello"]user@example.org[/email] +[email body="Sent from phpBB" subject="Hello" email="user@example.org"]...[/email] diff --git a/tests/text_processing/tickets_data/PHPBB3-10989.html b/tests/text_processing/tickets_data/PHPBB3-10989.html new file mode 100644 index 0000000000..cd24df60e5 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10989.html @@ -0,0 +1,8 @@ +<blockquote><div><cite>Lorem wrote:</cite>[quote="Lorem"<blockquote class="uncited"><div> Suspendisse iaculis porta tempor. Nulla.</div></blockquote> + Nullam a tortor sit amet.</div></blockquote> + Proin ac mi eget magna.<br> + +<blockquote><div><cite>Lorem wrote:</cite>Quisque fermentum tortor quis odio scelerisque consequat fermentum urna gravida. In semper vehicula condimentum. Donec suscipit ante imperdiet augue rhoncus.</div></blockquote> + +<br> +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas quis odio orci, sit amet semper.
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-10989.txt b/tests/text_processing/tickets_data/PHPBB3-10989.txt new file mode 100644 index 0000000000..dc2430f210 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-10989.txt @@ -0,0 +1,8 @@ +[quote="Lorem"][quote="Lorem"[quote] Suspendisse iaculis porta tempor. Nulla.[/quote] + Nullam a tortor sit amet.[/quote] + Proin ac mi eget magna. + +[quote="Lorem"]Quisque fermentum tortor quis odio scelerisque consequat fermentum urna gravida. In semper vehicula condimentum. Donec suscipit ante imperdiet augue rhoncus.[/quote] + + +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas quis odio orci, sit amet semper.
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-11153.html b/tests/text_processing/tickets_data/PHPBB3-11153.html new file mode 100644 index 0000000000..0f67ac4bc0 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-11153.html @@ -0,0 +1 @@ +<a href="mailto:user@example.org">...</a>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-11153.txt b/tests/text_processing/tickets_data/PHPBB3-11153.txt new file mode 100644 index 0000000000..d2794978d9 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-11153.txt @@ -0,0 +1 @@ +[myemail=user@example.org]...[/myemail]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-11153.xml b/tests/text_processing/tickets_data/PHPBB3-11153.xml new file mode 100644 index 0000000000..a7fc69520b --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-11153.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>myemail</value> + <value></value> + <value>1</value> + <value>[myemail={EMAIL}]{TEXT}[/myemail]</value> + <value><![CDATA[<a href="mailto:{EMAIL}">{TEXT}</a>]]></value> + <value><![CDATA[!\[myemail\=(([\w\!\#$\%\&'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%'\*\+\-\/\=\?\^\`{\|\}\~]|&)+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?))\](.*?)\[/myemail\]!ies]]></value> + <value><![CDATA['[myemail='.$this->bbcode_specialchars('${1}').':$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${2}')).'[/myemail:$uid]']]></value> + <value><![CDATA[!\[myemail\=(([\w\!\#$\%\&'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%'\*\+\-\/\=\?\^\`{\|\}\~]|&)+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)):$uid\](.*?)\[/myemail:$uid\]!s]]></value> + <value><![CDATA[<a href="mailto:${1}">${2}</a>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-11742.html b/tests/text_processing/tickets_data/PHPBB3-11742.html new file mode 100644 index 0000000000..e7890eef19 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-11742.html @@ -0,0 +1 @@ +<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code> tab</code></pre></div>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-11742.txt b/tests/text_processing/tickets_data/PHPBB3-11742.txt new file mode 100644 index 0000000000..db72e5dda0 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-11742.txt @@ -0,0 +1 @@ +[code] tab[/code]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-12195.html b/tests/text_processing/tickets_data/PHPBB3-12195.html new file mode 100644 index 0000000000..c286c0fee9 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-12195.html @@ -0,0 +1 @@ +<a href="//example.org/" class="postlink"><img src="//example.org/img.png" class="postimage" alt="Image"></a>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-12195.txt b/tests/text_processing/tickets_data/PHPBB3-12195.txt new file mode 100644 index 0000000000..b66dbd5d96 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-12195.txt @@ -0,0 +1 @@ +[url=//example.org/][img]//example.org/img.png[/img][/url]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-12221.html b/tests/text_processing/tickets_data/PHPBB3-12221.html new file mode 100644 index 0000000000..567f552e84 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-12221.html @@ -0,0 +1 @@ +<a href="https://example.com/test/#?javascript:lolhax" class="postlink">https://example.com/test/#?javascript:lolhax</a>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-12221.txt b/tests/text_processing/tickets_data/PHPBB3-12221.txt new file mode 100644 index 0000000000..01a0bf8667 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-12221.txt @@ -0,0 +1 @@ +https://example.com/test/#?javascript:lolhax
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13425.html b/tests/text_processing/tickets_data/PHPBB3-13425.html new file mode 100644 index 0000000000..9a042dc558 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13425.html @@ -0,0 +1 @@ +<blockquote class="uncited"><div><img class="smilies" src="phpBB/images/smilies/icon_lol.gif" alt=":lol:" title="Laughing"> starts with a smiley</div></blockquote>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13425.txt b/tests/text_processing/tickets_data/PHPBB3-13425.txt new file mode 100644 index 0000000000..8456410df5 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13425.txt @@ -0,0 +1 @@ +[quote]:lol: starts with a smiley[/quote]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13425.xml b/tests/text_processing/tickets_data/PHPBB3-13425.xml new file mode 100644 index 0000000000..cbdcaa7fb7 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13425.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>22</value> + <value>:lol:</value> + <value>Laughing</value> + <value>icon_lol.gif</value> + <value>15</value> + <value>17</value> + <value>22</value> + <value>1</value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-13451.html b/tests/text_processing/tickets_data/PHPBB3-13451.html new file mode 100644 index 0000000000..e0892c18a9 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13451.html @@ -0,0 +1 @@ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@example.org
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13451.txt b/tests/text_processing/tickets_data/PHPBB3-13451.txt new file mode 100644 index 0000000000..e0892c18a9 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13451.txt @@ -0,0 +1 @@ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@example.org
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13641.html b/tests/text_processing/tickets_data/PHPBB3-13641.html new file mode 100644 index 0000000000..1bd1c06dbb --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13641.html @@ -0,0 +1 @@ +<code>[color=#FF0000]</code> - <span style="color: #FF0000">red</span>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13641.txt b/tests/text_processing/tickets_data/PHPBB3-13641.txt new file mode 100644 index 0000000000..58f324715e --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13641.txt @@ -0,0 +1 @@ +[c][color=#FF0000][/c] - [color=#FF0000]red[/color]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13641.xml b/tests/text_processing/tickets_data/PHPBB3-13641.xml new file mode 100644 index 0000000000..451c5c69cd --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13641.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>c</value> + <value></value> + <value>1</value> + <value>[c]{TEXT}[/c]</value> + <value><![CDATA[<code>{TEXT}</code>]]></value> + <value><\[/c\]!ies]]></value> + <value><![CDATA['[c:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${1}')).'[/c:$uid]']]></value> + <value><\[/c:$uid\]!s]]></value> + <value><![CDATA[<code>${1}</code>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-13921.html b/tests/text_processing/tickets_data/PHPBB3-13921.html new file mode 100644 index 0000000000..6a9dc7f504 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13921.html @@ -0,0 +1 @@ +<span style="font-size: 200%; line-height: normal"></span><div style="text-align:center"><span style="font-size: 200%; line-height: normal">xxx</span></div>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13921.txt b/tests/text_processing/tickets_data/PHPBB3-13921.txt new file mode 100644 index 0000000000..392da0c3c8 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13921.txt @@ -0,0 +1 @@ +[size=200][center]xxx[/center][/size]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-13921.xml b/tests/text_processing/tickets_data/PHPBB3-13921.xml new file mode 100644 index 0000000000..8d39246bb4 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-13921.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>center</value> + <value></value> + <value>1</value> + <value>[center]{TEXT}[/center]</value> + <value><![CDATA[<div style="text-align:center">{TEXT}</div>]]></value> + <value>!\[center\](.*?)\[/center\]!ies</value> + <value>'[center:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${1}')).'[/center:$uid]'</value> + <value>!\[center:$uid\](.*?)\[/center:$uid\]!s</value> + <value><![CDATA[<div style="text-align:center">${1}</div>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-14405.html b/tests/text_processing/tickets_data/PHPBB3-14405.html new file mode 100644 index 0000000000..5e76e032ec --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-14405.html @@ -0,0 +1 @@ +[url=<a href="http://example.org" class="postlink">http://example.org</a>]...
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-14405.txt b/tests/text_processing/tickets_data/PHPBB3-14405.txt new file mode 100644 index 0000000000..7005b36b23 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-14405.txt @@ -0,0 +1 @@ +[url=http://example.org]...
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-3981.before.php b/tests/text_processing/tickets_data/PHPBB3-3981.before.php new file mode 100644 index 0000000000..1c326b52af --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-3981.before.php @@ -0,0 +1,21 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +function before_assert_phpbb3_3981($vars) +{ + if (!function_exists('idn_to_ascii')) + { + extract($vars); + $test->markTestSkipped('International URLs need idn_to_ascii()'); + } +} diff --git a/tests/text_processing/tickets_data/PHPBB3-3981.html b/tests/text_processing/tickets_data/PHPBB3-3981.html new file mode 100644 index 0000000000..e5f1b4561d --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-3981.html @@ -0,0 +1 @@ +<a href="http://www.xn--ndaaa.com" class="postlink">http://www.ööö.com</a>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-3981.txt b/tests/text_processing/tickets_data/PHPBB3-3981.txt new file mode 100644 index 0000000000..976823f1d1 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-3981.txt @@ -0,0 +1 @@ +[url]http://www.ööö.com[/url]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-7187.html b/tests/text_processing/tickets_data/PHPBB3-7187.html new file mode 100644 index 0000000000..9138779d29 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-7187.html @@ -0,0 +1 @@ +<blockquote class="uncited"><div><img class="smilies" src="phpBB/images/smilies/icon_e_geek.gif" alt=":geek:" title="Geek"> <img class="smilies" src="phpBB/images/smilies/icon_e_ugeek.gif" alt=":ugeek:" title="Uber Geek"></div></blockquote>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-7187.txt b/tests/text_processing/tickets_data/PHPBB3-7187.txt new file mode 100644 index 0000000000..584151a083 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-7187.txt @@ -0,0 +1 @@ +[quote]:geek: :ugeek:[/quote]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-7187.xml b/tests/text_processing/tickets_data/PHPBB3-7187.xml new file mode 100644 index 0000000000..d270b12619 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-7187.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>41</value> + <value>:geek:</value> + <value>Geek</value> + <value>icon_e_geek.gif</value> + <value>17</value> + <value>17</value> + <value>41</value> + <value>1</value> + </row> + <row> + <value>42</value> + <value>:ugeek:</value> + <value>Uber Geek</value> + <value>icon_e_ugeek.gif</value> + <value>17</value> + <value>18</value> + <value>42</value> + <value>1</value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-7275.after.php b/tests/text_processing/tickets_data/PHPBB3-7275.after.php new file mode 100644 index 0000000000..99f41d7839 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-7275.after.php @@ -0,0 +1,19 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +function after_assert_phpbb3_7275($vars) +{ + extract($vars); + decode_message($parsed_text); + $test->assertSame($original, $parsed_text); +} diff --git a/tests/text_processing/tickets_data/PHPBB3-7275.html b/tests/text_processing/tickets_data/PHPBB3-7275.html new file mode 100644 index 0000000000..12502833fd --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-7275.html @@ -0,0 +1 @@ +<div align="center"><img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" alt=":)" title="Smile"></div>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-7275.txt b/tests/text_processing/tickets_data/PHPBB3-7275.txt new file mode 100644 index 0000000000..8de97d67e0 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-7275.txt @@ -0,0 +1 @@ +[center]:)[/center]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-7275.xml b/tests/text_processing/tickets_data/PHPBB3-7275.xml new file mode 100644 index 0000000000..9e979afffb --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-7275.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>center</value> + <value></value> + <value>1</value> + <value>[center]{TEXT}[/center]</value> + <value><![CDATA[<div align="center">{TEXT}</div>]]></value> + <value>!\[center\](.*?)\[/center\]!ies</value> + <value><![CDATA['[center:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${1}')).'[/center:$uid]']]></value> + <value>!\[center:$uid\](.*?)\[/center:$uid\]!s</value> + <value><![CDATA[<div align="center">${1}</div>]]></value> + </row> + </table> + + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>4</value> + <value>:)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>4</value> + <value>1</value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-8419.html b/tests/text_processing/tickets_data/PHPBB3-8419.html new file mode 100644 index 0000000000..38df626a94 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-8419.html @@ -0,0 +1 @@ +<span style="font-style: italic"><span style="font-weight: bold"><span style="color: #FF0000">tę </span></span></span>przykład
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-8419.txt b/tests/text_processing/tickets_data/PHPBB3-8419.txt new file mode 100644 index 0000000000..dac47823b6 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-8419.txt @@ -0,0 +1 @@ +[ort]tę [/ort]przykład
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-8419.xml b/tests/text_processing/tickets_data/PHPBB3-8419.xml new file mode 100644 index 0000000000..2f1df345f9 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-8419.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>myemail</value> + <value></value> + <value>1</value> + <value>[ort]{TEXT}[/ort]</value> + <value><![CDATA[<span style="font-style: italic"><span style="font-weight: bold"><span style="color: #FF0000">{TEXT}</span></span></span>]]></value> + <value><\[/ort\]!ies]]></value> + <value><![CDATA['[ort:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${1}')).'[/ort:$uid]']]></value> + <value><\[/ort:$uid\]!s]]></value> + <value><![CDATA[<span style="font-style: italic"><span style="font-weight: bold"><span style="color: #FF0000">${1}</span></span></span>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-9073.html b/tests/text_processing/tickets_data/PHPBB3-9073.html new file mode 100644 index 0000000000..ff1f9fd0ce --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-9073.html @@ -0,0 +1,2 @@ +<a href="http://www.xxxx-xx-xxxx.com/" class="postlink">http://www.xxxx-xx-xxxx.com/</a><br> +<a href="http://www.xxxx-xx-xxxx.com/" class="postlink">http://www.xxxx-xx-xxxx.com/</a><br> diff --git a/tests/text_processing/tickets_data/PHPBB3-9073.txt b/tests/text_processing/tickets_data/PHPBB3-9073.txt new file mode 100644 index 0000000000..2c271173ce --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-9073.txt @@ -0,0 +1,2 @@ +http://www.some-ad-site.com/ +[url]http://www.some-ad-site.com/[/url] diff --git a/tests/text_processing/tickets_data/PHPBB3-9073.xml b/tests/text_processing/tickets_data/PHPBB3-9073.xml new file mode 100644 index 0000000000..d635d51ed1 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-9073.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_words"> + <column>word_id</column> + <column>word</column> + <column>replacement</column> + + <row> + <value>1</value> + <value>http://www.some-ad-site.com*</value> + <value>http://www.xxxx-xx-xxxx.com</value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-9377.html b/tests/text_processing/tickets_data/PHPBB3-9377.html new file mode 100644 index 0000000000..dcfb79c173 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-9377.html @@ -0,0 +1 @@ +<span style="color:red">red <span style="color:blue">blue</span> red</span>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-9377.txt b/tests/text_processing/tickets_data/PHPBB3-9377.txt new file mode 100644 index 0000000000..dfd71492c5 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-9377.txt @@ -0,0 +1 @@ +[red]red [blue]blue[/blue] red[/red]
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-9377.xml b/tests/text_processing/tickets_data/PHPBB3-9377.xml new file mode 100644 index 0000000000..1d8ee3d53f --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-9377.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>red</value> + <value></value> + <value>1</value> + <value>[red]{TEXT}[/red]</value> + <value><span style="color:red">{TEXT}</span></value> + <value>!\[red\](.*?)\[/red\]!ies</value> + <value>'[red:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/red:$uid]'</value> + <value>!\[red:$uid\](.*?)\[/red:$uid\]!s</value> + <value><span style="color:red">${1}</span></value> + </row> + + <row> + <value>14</value> + <value>blue</value> + <value></value> + <value>1</value> + <value>[blue]{TEXT}[/blue]</value> + <value><span style="color:blue">{TEXT}</span></value> + <value>!\[blue\](.*?)\[/blue\]!ies</value> + <value>'[blue:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/blue:$uid]'</value> + <value>!\[blue:$uid\](.*?)\[/blue:$uid\]!s</value> + <value><span style="color:blue">${1}</span></value> + </row> + </table> +</dataset> diff --git a/tests/text_processing/tickets_data/PHPBB3-9791.html b/tests/text_processing/tickets_data/PHPBB3-9791.html new file mode 100644 index 0000000000..3d0108c8a6 --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-9791.html @@ -0,0 +1 @@ +<a href="http://www.phpbb.com/community/search.php?keywords=bogus&terms=all&author=&fid%5B%5D=46&sc=1&sf=all&sr=posts&sk=t&sd=d&st=0&ch=300&t=0&submit=Search" class="postlink">http://www.phpbb.com/community/search.p ... mit=Search</a>
\ No newline at end of file diff --git a/tests/text_processing/tickets_data/PHPBB3-9791.txt b/tests/text_processing/tickets_data/PHPBB3-9791.txt new file mode 100644 index 0000000000..e29b20086d --- /dev/null +++ b/tests/text_processing/tickets_data/PHPBB3-9791.txt @@ -0,0 +1 @@ +http://www.phpbb.com/community/search.php?keywords=bogus&terms=all&author=&fid[]=46&sc=1&sf=all&sr=posts&sk=t&sd=d&st=0&ch=300&t=0&submit=Search
\ No newline at end of file diff --git a/tests/text_processing/tickets_test.php b/tests/text_processing/tickets_test.php new file mode 100644 index 0000000000..8c48a3f4a9 --- /dev/null +++ b/tests/text_processing/tickets_test.php @@ -0,0 +1,94 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once __DIR__ . '/../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../phpBB/includes/functions_content.php'; +require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php'; + +class phpbb_text_processing_tickets_test extends phpbb_test_case +{ + /** + * @dataProvider get_tickets_data + */ + public function test_tickets($ticket_id, $original, $expected, $fixture, $before_assert, $after_assert) + { + global $phpbb_container; + + $phpbb_container = new phpbb_mock_container_builder; + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, $fixture); + + $parser = $phpbb_container->get('text_formatter.parser'); + $renderer = $phpbb_container->get('text_formatter.renderer'); + + if (isset($before_assert)) + { + $test = $this; + $before_assert(get_defined_vars()); + } + + $parsed_text = $parser->parse($original); + + $this->assertSame($expected, $renderer->render($parsed_text)); + + if (isset($after_assert)) + { + $test = $this; + $after_assert(get_defined_vars()); + } + } + + public function get_tickets_data() + { + $tests = array(); + + foreach (glob(__DIR__ . '/tickets_data/*.txt') as $txt_filename) + { + $ticket_id = basename($txt_filename, '.txt'); + $html_filename = substr($txt_filename, 0, -3) . 'html'; + $xml_filename = substr($txt_filename, 0, -3) . 'xml'; + $before_filename = substr($txt_filename, 0, -3) . 'before.php'; + $after_filename = substr($txt_filename, 0, -3) . 'after.php'; + + if (!file_exists($xml_filename)) + { + $xml_filename = __DIR__ . '/../fixtures/empty.xml'; + } + + $before_assert = null; + if (file_exists($before_filename)) + { + include($before_filename); + $before_assert = 'before_assert_' . strtolower(str_replace('-', '_', $ticket_id)); + } + + $after_assert = null; + if (file_exists($after_filename)) + { + include($after_filename); + $after_assert = 'after_assert_' . strtolower(str_replace('-', '_', $ticket_id)); + } + + $tests[] = array( + $ticket_id, + file_get_contents($txt_filename), + file_get_contents($html_filename), + $xml_filename, + $before_assert, + $after_assert + ); + } + + return $tests; + } +} diff --git a/tests/text_reparser/fixtures/config_text.xml b/tests/text_reparser/fixtures/config_text.xml new file mode 100644 index 0000000000..ba8e1fcfcc --- /dev/null +++ b/tests/text_reparser/fixtures/config_text.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_config_text"> + <column>config_name</column> + <column>config_value</column> + </table> +</dataset> diff --git a/tests/text_reparser/manager_test.php b/tests/text_reparser/manager_test.php new file mode 100644 index 0000000000..df6adacb66 --- /dev/null +++ b/tests/text_reparser/manager_test.php @@ -0,0 +1,117 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +require_once __DIR__ . '/../mock/container_builder.php'; +require_once __DIR__ . '/../test_framework/phpbb_database_test_case.php'; + +class phpbb_text_reparser_manager_test extends phpbb_database_test_case +{ + /** @var \phpbb\config\config */ + protected $config; + + /** @var \phpbb\config\db_text */ + protected $config_text; + + /** @var \phpbb\textreparser\manager */ + protected $reparser_manager; + + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/config_text.xml'); + } + + public function setUp() + { + parent::setUp(); + + $this->config = new \phpbb\config\config(array( + 'test_reparser_cron_interval' => 0, + 'my_reparser_cron_interval' => 100, + )); + + $db = $this->new_dbal(); + $this->config_text = new \phpbb\config\db_text($db, 'phpbb_config_text'); + + $service_collection = new \phpbb\di\service_collection(new phpbb_mock_container_builder()); + $service_collection->add('test_reparser'); + $service_collection->add('another_reparser'); + $service_collection->add('my_reparser'); + + $this->reparser_manager = new \phpbb\textreparser\manager($this->config, $this->config_text, $service_collection); + } + + public function test_get_resume_data() + { + $resume_data = array( + 'test_reparser' => array( + 'range-min' => 0, + 'range-max' => 100, + 'range-size' => 50, + ), + ); + $this->config_text->set('reparser_resume', serialize($resume_data)); + + $this->assert_array_content_equals($resume_data['test_reparser'], $this->reparser_manager->get_resume_data('test_reparser')); + $this->assertEmpty($this->reparser_manager->get_resume_data('another_reparser')); + } + + public function test_update_resume_data() + { + $resume_data = array( + 'test_reparser' => array( + 'range-min' => 0, + 'range-max' => 100, + 'range-size' => 50, + ), + ); + $this->config_text->set('reparser_resume', serialize($resume_data)); + + $this->reparser_manager->update_resume_data('another_reparser', 5, 20, 10, false); + $this->assert_array_content_equals($resume_data, unserialize($this->config_text->get('reparser_resume'))); + + $this->reparser_manager->update_resume_data('test_reparser', 0, 50, 50); + $resume_data = array( + 'test_reparser' => array( + 'range-min' => 0, + 'range-max' => 50, + 'range-size' => 50, + ), + 'another_reparser' => array( + 'range-min' => 5, + 'range-max' => 20, + 'range-size' => 10, + ), + ); + $this->assert_array_content_equals($resume_data, unserialize($this->config_text->get('reparser_resume'))); + } + + public function test_schedule() + { + $this->reparser_manager->schedule('no_reparser', 21); + $this->assertArrayNotHasKey('no_reparser_cron_interval', $this->config); + + $this->reparser_manager->schedule('another_reparser', 42); + $this->assertArrayNotHasKey('another_reparser_cron_interval', $this->config); + + $this->reparser_manager->schedule('test_reparser', 20); + $this->assertEquals(20, $this->config['test_reparser_cron_interval']); + } + + public function test_schedule_all() + { + $this->reparser_manager->schedule_all(180); + $this->assertEquals(180, $this->config['test_reparser_cron_interval']); + $this->assertEquals(180, $this->config['my_reparser_cron_interval']); + $this->assertArrayNotHasKey('another_reparser_cron_interval', $this->config); + } +} diff --git a/tests/text_reparser/plugins/contact_admin_info_test.php b/tests/text_reparser/plugins/contact_admin_info_test.php new file mode 100644 index 0000000000..1dc03834b6 --- /dev/null +++ b/tests/text_reparser/plugins/contact_admin_info_test.php @@ -0,0 +1,96 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +require_once __DIR__ . '/../../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../../phpBB/includes/functions_content.php'; +require_once __DIR__ . '/../../test_framework/phpbb_database_test_case.php'; + +class phpbb_textreparser_contact_admin_info_test extends phpbb_database_test_case +{ + protected $db; + + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/contact_admin_info.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\contact_admin_info(new \phpbb\config\db_text($this->db, CONFIG_TEXT_TABLE)); + } + + protected function get_rows() + { + $sql = 'SELECT config_name, config_value + FROM ' . CONFIG_TEXT_TABLE . ' + ORDER BY config_name'; + $result = $this->db->sql_query($sql); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + return $rows; + } + + public function setUp() + { + global $config; + if (!isset($config)) + { + $config = new \phpbb\config\config(array()); + } + $this->get_test_case_helpers()->set_s9e_services(); + $this->db = $this->new_dbal(); + parent::setUp(); + } + + public function test_get_max_id() + { + $reparser = $this->get_reparser(); + $this->assertEquals(1, $reparser->get_max_id()); + } + + public function test_dry_run() + { + $old_rows = $this->get_rows(); + $reparser = $this->get_reparser(); + $reparser->disable_save(); + $reparser->reparse_range(1, 1); + $new_rows = $this->get_rows(); + $this->assertEquals($old_rows, $new_rows); + } + + public function test_reparse() + { + $reparser = $this->get_reparser(); + $reparser->enable_save(); + $reparser->reparse_range(1, 1); + $expected = array( + array( + 'config_name' => 'contact_admin_info', + 'config_value' => '<r><EMAIL email="admin@example.org"><s>[email]</s>admin@example.org<e>[/email]</e></EMAIL></r>', + ), + array( + 'config_name' => 'contact_admin_info_bitfield', + 'config_value' => 'ACA=', + ), + array( + 'config_name' => 'contact_admin_info_flags', + 'config_value' => '7', + ), + array( + 'config_name' => 'contact_admin_info_uid', + 'config_value' => '1a2hbwf5', + ), + ); + $this->assertEquals($expected, $this->get_rows()); + } +} diff --git a/tests/text_reparser/plugins/fixtures/contact_admin_info.xml b/tests/text_reparser/plugins/fixtures/contact_admin_info.xml new file mode 100644 index 0000000000..13cd82b1a4 --- /dev/null +++ b/tests/text_reparser/plugins/fixtures/contact_admin_info.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_config_text"> + <column>config_name</column> + <column>config_value</column> + <row> + <value>contact_admin_info</value> + <value>[email:1a2hbwf5]admin@example.org[/email:1a2hbwf5]</value> + </row> + <row> + <value>contact_admin_info_uid</value> + <value>1a2hbwf5</value> + </row> + <row> + <value>contact_admin_info_bitfield</value> + <value>ACA=</value> + </row> + <row> + <value>contact_admin_info_flags</value> + <value>7</value> + </row> + </table> +</dataset> diff --git a/tests/text_reparser/plugins/fixtures/forums.xml b/tests/text_reparser/plugins/fixtures/forums.xml new file mode 100644 index 0000000000..c12c8d6d48 --- /dev/null +++ b/tests/text_reparser/plugins/fixtures/forums.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_forums"> + <column>forum_id</column> + <column>forum_parents</column> + <column>forum_desc</column> + <column>forum_desc_uid</column> + <column>forum_desc_options</column> + <column>forum_rules</column> + <column>forum_rules_uid</column> + <column>forum_rules_options</column> + <row> + <value>1</value> + <value></value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + <value>0</value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + <value>0</value> + </row> + <row> + <value>2</value> + <value></value> + <value>[b]Not bold[/b] :) http://example.org</value> + <value>abcd1234</value> + <value>0</value> + <value>[b]Not bold[/b] :) http://example.org</value> + <value>abcd1234</value> + <value>0</value> + </row> + <row> + <value>3</value> + <value></value> + <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value> + <value>abcd1234</value> + <value>1</value> + <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value> + <value>abcd1234</value> + <value>1</value> + </row> + <row> + <value>4</value> + <value></value> + <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value> + <value>abcd1234</value> + <value>2</value> + <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value> + <value>abcd1234</value> + <value>2</value> + </row> + <row> + <value>5</value> + <value></value> + <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + <value>abcd1234</value> + <value>4</value> + <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + <value>abcd1234</value> + <value>4</value> + </row> + <row> + <value>6</value> + <value></value> + <value><![CDATA[[flash=123,345:abcd1234]http://example.org/flash.swf[/flash:abcd1234]]]></value> + <value>abcd1234</value> + <value>1</value> + <value><![CDATA[[flash=123,345:abcd1234]http://example.org/flash.swf[/flash:abcd1234]]]></value> + <value>abcd1234</value> + <value>1</value> + </row> + <row> + <value>7</value> + <value></value> + <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value> + <value>abcd1234</value> + <value>0</value> + <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value> + <value>abcd1234</value> + <value>0</value> + </row> + <row> + <value>8</value> + <value></value> + <value><![CDATA[[img:abcd1234]http://example.org/img.png[/img:abcd1234]]]></value> + <value>abcd1234</value> + <value>1</value> + <value><![CDATA[[img:abcd1234]http://example.org/img.png[/img:abcd1234]]]></value> + <value>abcd1234</value> + <value>1</value> + </row> + <row> + <value>9</value> + <value></value> + <value><![CDATA[[img]http://example.org/img.png[/img]]]></value> + <value>abcd1234</value> + <value>0</value> + <value><![CDATA[[img]http://example.org/img.png[/img]]]></value> + <value>abcd1234</value> + <value>0</value> + </row> + <row> + <value>1000</value> + <value></value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + <value>0</value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + <value>0</value> + </row> + </table> +</dataset> diff --git a/tests/text_reparser/plugins/fixtures/groups.xml b/tests/text_reparser/plugins/fixtures/groups.xml new file mode 100644 index 0000000000..15151426bc --- /dev/null +++ b/tests/text_reparser/plugins/fixtures/groups.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_groups"> + <column>group_id</column> + <column>group_desc</column> + <column>group_desc_options</column> + <column>group_desc_uid</column> + <row> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + <value>7</value> + <value>abcd1234</value> + </row> + <row> + <value>2</value> + <value>[b]Not bold[/b] :) http://example.org</value> + <value>0</value> + <value>abcd1234</value> + </row> + <row> + <value>3</value> + <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value> + <value>1</value> + <value>abcd1234</value> + </row> + <row> + <value>4</value> + <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value> + <value>2</value> + <value>abcd1234</value> + </row> + <row> + <value>5</value> + <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + <value>4</value> + <value>abcd1234</value> + </row> + <row> + <value>6</value> + <value><![CDATA[[flash=123,345:abcd1234]http://example.org/flash.swf[/flash:abcd1234]]]></value> + <value>1</value> + <value>abcd1234</value> + </row> + <row> + <value>7</value> + <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value> + <value>1</value> + <value>abcd1234</value> + </row> + <row> + <value>8</value> + <value><![CDATA[[img:abcd1234]http://example.org/img.png[/img:abcd1234]]]></value> + <value>1</value> + <value>abcd1234</value> + </row> + <row> + <value>9</value> + <value><![CDATA[[img]http://example.org/img.png[/img]]]></value> + <value>1</value> + <value>abcd1234</value> + </row> + <row> + <value>1000</value> + <value>This row should be [b]ignored[/b]</value> + <value>7</value> + <value>abcd1234</value> + </row> + </table> +</dataset> diff --git a/tests/text_reparser/plugins/fixtures/poll_options.xml b/tests/text_reparser/plugins/fixtures/poll_options.xml new file mode 100644 index 0000000000..48ba024315 --- /dev/null +++ b/tests/text_reparser/plugins/fixtures/poll_options.xml @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_poll_options"> + <column>poll_option_id</column> + <column>topic_id</column> + <column>poll_option_text</column> + <row> + <value>1</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + </row> + <row> + <value>2</value> + <value>1</value> + <value>This row should be [b:abcd1234]ignored[/b:abcd1234]</value> + </row> + <row> + <value>1</value> + <value>2</value> + <value>[b:abcd1234]Bold[/b:abcd1234]</value> + </row> + <row> + <value>2</value> + <value>2</value> + <value><![CDATA[<!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) -->]]></value> + </row> + <row> + <value>3</value> + <value>2</value> + <value><![CDATA[<!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + </row> + <row> + <value>1</value> + <value>11</value> + <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value> + </row> + <row> + <value>1</value> + <value>12</value> + <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value> + </row> + <row> + <value>1</value> + <value>13</value> + <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + </row> + <row> + <value>1</value> + <value>123</value> + <value>This row should be [b]ignored[/b]</value> + </row> + <row> + <value>2</value> + <value>123</value> + <value>This row should be [b:abcd1234]ignored[/b:abcd1234]</value> + </row> + </table> + <table name="phpbb_posts"> + <column>post_id</column> + <column>enable_bbcode</column> + <column>enable_smilies</column> + <column>enable_magic_url</column> + <column>post_text</column> + <column>bbcode_uid</column> + <row> + <value>1</value> + <value>1</value> + <value>1</value> + <value>1</value> + <value></value> + <value>abcd1234</value> + </row> + <row> + <value>11</value> + <value>1</value> + <value>0</value> + <value>0</value> + <value></value> + <value>abcd1234</value> + </row> + <row> + <value>12</value> + <value>0</value> + <value>1</value> + <value>0</value> + <value></value> + <value>abcd1234</value> + </row> + <row> + <value>13</value> + <value>0</value> + <value>0</value> + <value>1</value> + <value></value> + <value>abcd1234</value> + </row> + </table> + <table name="phpbb_topics"> + <column>topic_id</column> + <column>topic_first_post_id</column> + <column>poll_title</column> + <row> + <value>1</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + </row> + <row> + <value>2</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + </row> + <row> + <value>11</value> + <value>11</value> + <value>BBCode</value> + </row> + <row> + <value>12</value> + <value>12</value> + <value>Smilies</value> + </row> + <row> + <value>13</value> + <value>13</value> + <value>Magic URLs</value> + </row> + <row> + <value>123</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + </row> + </table> +</dataset> diff --git a/tests/text_reparser/plugins/fixtures/polls.xml b/tests/text_reparser/plugins/fixtures/polls.xml new file mode 100644 index 0000000000..2960d640a9 --- /dev/null +++ b/tests/text_reparser/plugins/fixtures/polls.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_posts"> + <column>post_id</column> + <column>enable_bbcode</column> + <column>enable_smilies</column> + <column>enable_magic_url</column> + <column>post_text</column> + <column>bbcode_uid</column> + <row> + <value>1</value> + <value>0</value> + <value>0</value> + <value>0</value> + <value></value> + <value>abcd1234</value> + </row> + <row> + <value>2</value> + <value>1</value> + <value>0</value> + <value>0</value> + <value></value> + <value>abcd1234</value> + </row> + <row> + <value>3</value> + <value>0</value> + <value>1</value> + <value>0</value> + <value></value> + <value>abcd1234</value> + </row> + <row> + <value>4</value> + <value>0</value> + <value>0</value> + <value>1</value> + <value></value> + <value>abcd1234</value> + </row> + </table> + <table name="phpbb_topics"> + <column>topic_id</column> + <column>topic_first_post_id</column> + <column>poll_title</column> + <row> + <value>1</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + </row> + <row> + <value>2</value> + <value>1</value> + <value>[b]Not bold[/b] :) http://example.org</value> + </row> + <row> + <value>3</value> + <value>2</value> + <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value> + </row> + <row> + <value>4</value> + <value>3</value> + <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value> + </row> + <row> + <value>5</value> + <value>4</value> + <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + </row> + <row> + <value>6</value> + <value>2</value> + <value><![CDATA[[flash=123,345:abcd1234]http://example.org/flash.swf[/flash:abcd1234]]]></value> + </row> + <row> + <value>7</value> + <value>1</value> + <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value> + </row> + <row> + <value>8</value> + <value>2</value> + <value><![CDATA[[img:abcd1234]http://example.org/img.png[/img:abcd1234]]]></value> + </row> + <row> + <value>9</value> + <value>1</value> + <value><![CDATA[[img]http://example.org/img.png[/img]]]></value> + </row> + <row> + <value>1000</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + </row> + </table> +</dataset> diff --git a/tests/text_reparser/plugins/fixtures/posts.xml b/tests/text_reparser/plugins/fixtures/posts.xml new file mode 100644 index 0000000000..ec31747ed9 --- /dev/null +++ b/tests/text_reparser/plugins/fixtures/posts.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_posts"> + <column>post_id</column> + <column>enable_bbcode</column> + <column>enable_smilies</column> + <column>enable_magic_url</column> + <column>post_text</column> + <column>bbcode_uid</column> + <row> + <value>1</value> + <value>1</value> + <value>1</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + </row> + <row> + <value>2</value> + <value>0</value> + <value>0</value> + <value>0</value> + <value>[b]Not bold[/b] :) http://example.org</value> + <value>abcd1234</value> + </row> + <row> + <value>3</value> + <value>1</value> + <value>0</value> + <value>0</value> + <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value> + <value>abcd1234</value> + </row> + <row> + <value>4</value> + <value>0</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value> + <value>abcd1234</value> + </row> + <row> + <value>5</value> + <value>0</value> + <value>0</value> + <value>1</value> + <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + <value>abcd1234</value> + </row> + <row> + <value>6</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[flash=123,345:abcd1234]http://example.org/flash.swf[/flash:abcd1234]]]></value> + <value>abcd1234</value> + </row> + <row> + <value>7</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value> + <value>abcd1234</value> + </row> + <row> + <value>8</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[img:abcd1234]http://example.org/img.png[/img:abcd1234]]]></value> + <value>abcd1234</value> + </row> + <row> + <value>9</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[img]http://example.org/img.png[/img]]]></value> + <value>abcd1234</value> + </row> + <row> + <value>1000</value> + <value>1</value> + <value>1</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + </row> + </table> +</dataset> diff --git a/tests/text_reparser/plugins/fixtures/privmsgs.xml b/tests/text_reparser/plugins/fixtures/privmsgs.xml new file mode 100644 index 0000000000..4049b9890a --- /dev/null +++ b/tests/text_reparser/plugins/fixtures/privmsgs.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_privmsgs"> + <column>msg_id</column> + <column>enable_bbcode</column> + <column>enable_smilies</column> + <column>enable_magic_url</column> + <column>message_text</column> + <column>bbcode_uid</column> + <column>to_address</column> + <column>bcc_address</column> + <row> + <value>1</value> + <value>1</value> + <value>1</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>2</value> + <value>0</value> + <value>0</value> + <value>0</value> + <value>[b]Not bold[/b] :) http://example.org</value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>3</value> + <value>1</value> + <value>0</value> + <value>0</value> + <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>4</value> + <value>0</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>5</value> + <value>0</value> + <value>0</value> + <value>1</value> + <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>6</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[flash=123,345:abcd1234]http://example.org/flash.swf[/flash:abcd1234]]]></value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>7</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>8</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[img:abcd1234]http://example.org/img.png[/img:abcd1234]]]></value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>9</value> + <value>1</value> + <value>1</value> + <value>0</value> + <value><![CDATA[[img]http://example.org/img.png[/img]]]></value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + <row> + <value>1000</value> + <value>1</value> + <value>1</value> + <value>1</value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + <value></value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/text_reparser/plugins/fixtures/users.xml b/tests/text_reparser/plugins/fixtures/users.xml new file mode 100644 index 0000000000..60c623b6b1 --- /dev/null +++ b/tests/text_reparser/plugins/fixtures/users.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_users"> + <column>user_id</column> + <column>user_permissions</column> + <column>username_clean</column> + <column>user_options</column> + <column>user_sig</column> + <column>user_sig_bbcode_uid</column> + <row> + <value>1</value> + <value></value> + <value>user1</value> + <value>230271</value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + </row> + <row> + <value>2</value> + <value></value> + <value>user2</value> + <value>895</value> + <value>[b]Not bold[/b] :) http://example.org</value> + <value>abcd1234</value> + </row> + <row> + <value>3</value> + <value></value> + <value>user3</value> + <value>33663</value> + <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value> + <value>abcd1234</value> + </row> + <row> + <value>4</value> + <value></value> + <value>user4</value> + <value>66431</value> + <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value> + <value>abcd1234</value> + </row> + <row> + <value>5</value> + <value></value> + <value>user5</value> + <value>131967</value> + <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value> + <value>abcd1234</value> + </row> + <row> + <value>6</value> + <value></value> + <value>user6</value> + <value>99199</value> + <value><![CDATA[[flash=123,345:abcd1234]http://example.org/flash.swf[/flash:abcd1234]]]></value> + <value>abcd1234</value> + </row> + <row> + <value>7</value> + <value></value> + <value>user7</value> + <value>99199</value> + <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value> + <value>abcd1234</value> + </row> + <row> + <value>8</value> + <value></value> + <value>user8</value> + <value>99199</value> + <value><![CDATA[[img:abcd1234]http://example.org/img.png[/img:abcd1234]]]></value> + <value>abcd1234</value> + </row> + <row> + <value>9</value> + <value></value> + <value>user9</value> + <value>99199</value> + <value><![CDATA[[img]http://example.org/img.png[/img]]]></value> + <value>abcd1234</value> + </row> + <row> + <value>1000</value> + <value></value> + <value>user1000</value> + <value>230271</value> + <value>This row should be [b]ignored[/b]</value> + <value>abcd1234</value> + </row> + </table> +</dataset> diff --git a/tests/text_reparser/plugins/forum_description_test.php b/tests/text_reparser/plugins/forum_description_test.php new file mode 100644 index 0000000000..57166e6a3c --- /dev/null +++ b/tests/text_reparser/plugins/forum_description_test.php @@ -0,0 +1,26 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +include_once __DIR__ . '/test_row_based_plugin.php'; + +class phpbb_textreparser_forum_description_test extends phpbb_textreparser_test_row_based_plugin +{ + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/forums.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\forum_description($this->db, FORUMS_TABLE); + } +} diff --git a/tests/text_reparser/plugins/forum_rules_test.php b/tests/text_reparser/plugins/forum_rules_test.php new file mode 100644 index 0000000000..72e4e98876 --- /dev/null +++ b/tests/text_reparser/plugins/forum_rules_test.php @@ -0,0 +1,26 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +include_once __DIR__ . '/test_row_based_plugin.php'; + +class phpbb_textreparser_forum_rules_test extends phpbb_textreparser_test_row_based_plugin +{ + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/forums.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\forum_rules($this->db, FORUMS_TABLE); + } +} diff --git a/tests/text_reparser/plugins/group_description_test.php b/tests/text_reparser/plugins/group_description_test.php new file mode 100644 index 0000000000..babfc7e02f --- /dev/null +++ b/tests/text_reparser/plugins/group_description_test.php @@ -0,0 +1,26 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +include_once __DIR__ . '/test_row_based_plugin.php'; + +class phpbb_textreparser_group_description_test extends phpbb_textreparser_test_row_based_plugin +{ + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/groups.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\group_description($this->db, GROUPS_TABLE); + } +} diff --git a/tests/text_reparser/plugins/pm_text_test.php b/tests/text_reparser/plugins/pm_text_test.php new file mode 100644 index 0000000000..6dc1a9cb4c --- /dev/null +++ b/tests/text_reparser/plugins/pm_text_test.php @@ -0,0 +1,26 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +include_once __DIR__ . '/test_row_based_plugin.php'; + +class phpbb_textreparser_pm_text_test extends phpbb_textreparser_test_row_based_plugin +{ + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/privmsgs.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\pm_text($this->db, PRIVMSGS_TABLE); + } +} diff --git a/tests/text_reparser/plugins/poll_option_test.php b/tests/text_reparser/plugins/poll_option_test.php new file mode 100644 index 0000000000..dfa3a030ed --- /dev/null +++ b/tests/text_reparser/plugins/poll_option_test.php @@ -0,0 +1,130 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +require_once __DIR__ . '/../../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../../phpBB/includes/functions_content.php'; +require_once __DIR__ . '/../../test_framework/phpbb_database_test_case.php'; + +class phpbb_textreparser_poll_option_test extends phpbb_database_test_case +{ + protected $db; + + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/poll_options.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\poll_option($this->db); + } + + protected function get_rows() + { + $sql = 'SELECT topic_id, poll_option_id, poll_option_text + FROM ' . POLL_OPTIONS_TABLE . ' + ORDER BY topic_id, poll_option_id'; + $result = $this->db->sql_query($sql); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + return $rows; + } + + public function setUp() + { + global $config; + if (!isset($config)) + { + $config = new \phpbb\config\config(array()); + } + $this->get_test_case_helpers()->set_s9e_services(); + $this->db = $this->new_dbal(); + parent::setUp(); + } + + public function test_get_max_id() + { + $reparser = $this->get_reparser(); + $this->assertEquals(123, $reparser->get_max_id()); + } + + public function test_dry_run() + { + $old_rows = $this->get_rows(); + $reparser = $this->get_reparser(); + $reparser->disable_save(); + $reparser->reparse_range(1, 1); + $new_rows = $this->get_rows(); + $this->assertEquals($old_rows, $new_rows); + } + + public function testReparse() + { + $reparser = $this->get_reparser(); + $reparser->enable_save(); + $reparser->reparse_range(2, 13); + $expected = array( + array( + 'topic_id' => 1, + 'poll_option_id' => 1, + 'poll_option_text' => 'This row should be [b]ignored[/b]', + ), + array( + 'topic_id' => 1, + 'poll_option_id' => 2, + 'poll_option_text' => 'This row should be [b:abcd1234]ignored[/b:abcd1234]', + ), + array( + 'topic_id' => 2, + 'poll_option_id' => 1, + 'poll_option_text' => '<r><B><s>[b]</s>Bold<e>[/b]</e></B></r>', + ), + array( + 'topic_id' => 2, + 'poll_option_id' => 2, + 'poll_option_text' => '<r><E>:)</E></r>', + ), + array( + 'topic_id' => 2, + 'poll_option_id' => 3, + 'poll_option_text' => '<r><URL url="http://example.org">http://example.org</URL></r>', + ), + array( + 'topic_id' => 11, + 'poll_option_id' => 1, + 'poll_option_text' => '<r><B><s>[b]</s>Bold<e>[/b]</e></B> :) http://example.org</r>', + ), + array( + 'topic_id' => 12, + 'poll_option_id' => 1, + 'poll_option_text' => '<r>[b]Not bold[/b] <E>:)</E> http://example.org</r>', + ), + array( + 'topic_id' => 13, + 'poll_option_id' => 1, + 'poll_option_text' => '<r>[b]Not bold[/b] :) <URL url="http://example.org">http://example.org</URL></r>', + ), + array( + 'topic_id' => 123, + 'poll_option_id' => 1, + 'poll_option_text' => 'This row should be [b]ignored[/b]', + ), + array( + 'topic_id' => 123, + 'poll_option_id' => 2, + 'poll_option_text' => 'This row should be [b:abcd1234]ignored[/b:abcd1234]', + ), + ); + $this->assertEquals($expected, $this->get_rows()); + } +} diff --git a/tests/text_reparser/plugins/poll_title_test.php b/tests/text_reparser/plugins/poll_title_test.php new file mode 100644 index 0000000000..046b6019c8 --- /dev/null +++ b/tests/text_reparser/plugins/poll_title_test.php @@ -0,0 +1,26 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +include_once __DIR__ . '/test_row_based_plugin.php'; + +class phpbb_textreparser_poll_title_test extends phpbb_textreparser_test_row_based_plugin +{ + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/polls.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\poll_title($this->db, TOPICS_TABLE); + } +} diff --git a/tests/text_reparser/plugins/post_text_test.php b/tests/text_reparser/plugins/post_text_test.php new file mode 100644 index 0000000000..8ea71e65f5 --- /dev/null +++ b/tests/text_reparser/plugins/post_text_test.php @@ -0,0 +1,26 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +include_once __DIR__ . '/test_row_based_plugin.php'; + +class phpbb_textreparser_post_text_test extends phpbb_textreparser_test_row_based_plugin +{ + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/posts.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\post_text($this->db, POSTS_TABLE); + } +} diff --git a/tests/text_reparser/plugins/test_row_based_plugin.php b/tests/text_reparser/plugins/test_row_based_plugin.php new file mode 100644 index 0000000000..e8218dfdd6 --- /dev/null +++ b/tests/text_reparser/plugins/test_row_based_plugin.php @@ -0,0 +1,151 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +require_once __DIR__ . '/../../../phpBB/includes/functions.php'; +require_once __DIR__ . '/../../../phpBB/includes/functions_content.php'; +require_once __DIR__ . '/../../test_framework/phpbb_database_test_case.php'; + +abstract class phpbb_textreparser_test_row_based_plugin extends phpbb_database_test_case +{ + protected $db; + + abstract protected function get_reparser(); + + protected function get_rows(array $ids) + { + $reparser = $this->get_reparser(); + $columns = $reparser->get_columns(); + + $reflection_reparser = new ReflectionClass(get_class($reparser)); + $table_property = $reflection_reparser->getProperty('table'); + $table_property->setAccessible(true); + + $sql = 'SELECT ' . $columns['id'] . ' AS id, ' . $columns['text'] . ' AS text + FROM ' . $table_property->getValue($reparser) . ' + WHERE ' . $this->db->sql_in_set($columns['id'], $ids) . ' + ORDER BY id'; + $result = $this->db->sql_query($sql); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + return $rows; + } + + public function setUp() + { + global $config; + if (!isset($config)) + { + $config = new \phpbb\config\config(array()); + } + $this->get_test_case_helpers()->set_s9e_services(); + $this->db = $this->new_dbal(); + parent::setUp(); + } + + public function test_get_max_id() + { + $reparser = $this->get_reparser(); + $this->assertEquals(1000, $reparser->get_max_id()); + } + + public function test_dry_run() + { + $old_rows = $this->get_rows(array(1)); + $reparser = $this->get_reparser(); + $reparser->disable_save(); + $reparser->reparse_range(1, 1); + $new_rows = $this->get_rows(array(1)); + $this->assertEquals($old_rows, $new_rows); + } + + /** + * @dataProvider get_reparse_tests + */ + public function test_reparse($min_id, $max_id, $expected) + { + $reparser = $this->get_reparser(); + $reparser->reparse_range($min_id, $max_id); + + $ids = array(); + foreach ($expected as $row) + { + $ids[] = $row['id']; + } + + $this->assertEquals($expected, $this->get_rows($ids)); + } + + public function get_reparse_tests() + { + return array( + array( + 2, + 5, + array( + array( + 'id' => '1', + 'text' => 'This row should be [b]ignored[/b]', + ), + array( + 'id' => '2', + 'text' => '<t>[b]Not bold[/b] :) http://example.org</t>', + ), + array( + 'id' => '3', + 'text' => '<r><B><s>[b]</s>Bold<e>[/b]</e></B> :) http://example.org</r>', + ), + array( + 'id' => '4', + 'text' => '<r>[b]Not bold[/b] <E>:)</E> http://example.org</r>', + ), + array( + 'id' => '5', + 'text' => '<r>[b]Not bold[/b] :) <URL url="http://example.org">http://example.org</URL></r>', + ), + array( + 'id' => '1000', + 'text' => 'This row should be [b]ignored[/b]', + ), + ) + ), + array( + 6, + 7, + array( + array( + 'id' => '6', + 'text' => '<r><FLASH height="345" url="http://example.org/flash.swf" width="123"><s>[flash=123,345]</s>http://example.org/flash.swf<e>[/flash]</e></FLASH></r>', + ), + array( + 'id' => '7', + 'text' => '<t>[flash=123,345]http://example.org/flash.swf[/flash]</t>', + ), + ) + ), + array( + 8, + 9, + array( + array( + 'id' => '8', + 'text' => '<r><IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG></r>', + ), + array( + 'id' => '9', + 'text' => '<t>[img]http://example.org/img.png[/img]</t>', + ), + ) + ), + ); + } +} diff --git a/tests/text_reparser/plugins/user_signature_test.php b/tests/text_reparser/plugins/user_signature_test.php new file mode 100644 index 0000000000..5b66f2788a --- /dev/null +++ b/tests/text_reparser/plugins/user_signature_test.php @@ -0,0 +1,26 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +include_once __DIR__ . '/test_row_based_plugin.php'; + +class phpbb_textreparser_user_signature_test extends phpbb_textreparser_test_row_based_plugin +{ + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/users.xml'); + } + + protected function get_reparser() + { + return new \phpbb\textreparser\plugins\user_signature($this->db, USERS_TABLE); + } +} diff --git a/tests/tree/nestedset_forum_base.php b/tests/tree/nestedset_forum_base.php index c56be1f81e..647fcef2af 100644 --- a/tests/tree/nestedset_forum_base.php +++ b/tests/tree/nestedset_forum_base.php @@ -59,7 +59,6 @@ class phpbb_tests_tree_nestedset_forum_base extends phpbb_database_test_case global $config; $config = $this->config = new \phpbb\config\config(array('nestedset_forum_lock' => 0)); - set_config(null, null, null, $this->config); $this->lock = new \phpbb\lock\db('nestedset_forum_lock', $this->config, $this->db); $this->set = new \phpbb\tree\nestedset_forum($this->db, $this->lock, 'phpbb_forums'); diff --git a/tests/ui/permission_roles_test.php b/tests/ui/permission_roles_test.php new file mode 100644 index 0000000000..3501124fc1 --- /dev/null +++ b/tests/ui/permission_roles_test.php @@ -0,0 +1,90 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +/** +* @group ui +*/ +class ui_permission_roles_test extends phpbb_ui_test_case +{ + + public function test_permission_roles() + { + $this->login(); + $this->admin_login(); + $this->add_lang('acp/permissions'); + $this->visit('adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid); + + // Select forums + $elements = self::find_element('cssSelector', 'select#forum') + ->findElements(\Facebook\WebDriver\WebDriverBy::tagName('option')); + + foreach ($elements as $element) + { + $element->click(); + } + self::find_element('cssSelector', 'form#select_victim') + ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=submit]')) + ->click(); + + // Select administrators and guests + $groups_form = self::find_element('cssSelector', 'form#groups'); + $elements = $groups_form + ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('select')) + ->findElements(\Facebook\WebDriver\WebDriverBy::tagName('option')); + + foreach ($elements as $element) + { + if ($element->getText() === 'Administrators' || $element->getText() === 'Guests') + { + $element->click(); + } + } + $groups_form->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[name=submit_edit_options]'))->click(); + + $first_fieldset = self::find_element('cssSelector', '#perm11'); + $this->assertEquals('none', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display')); + $first_fieldset + ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle')) + ->click(); + $this->assertEquals('block', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display')); + $lis = $first_fieldset + ->findElements(\Facebook\WebDriver\WebDriverBy::cssSelector('ul > li')); + + foreach ($lis as $li) + { + if ($li->getAttribute('data-id') == 18) + { + $li->click(); + + break; + } + } + $this->assertEquals('none', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display')); + $this->assertEquals(18, $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value')); + $this->assertEquals($this->lang('ROLE_FORUM_LIMITED'), $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText()); + + // Check that admin settings didn't get changed + $second_fieldset = self::find_element('cssSelector', '#perm10'); + $this->assertEquals('none', $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display')); + // Full access = 14 + $this->assertEquals(14, $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value')); + $this->assertEquals($this->lang('ROLE_FORUM_FULL'), $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText()); + + // Check that category settings were not modified + $category_fieldset = self::find_element('cssSelector', '#perm00'); + $this->assertEquals('none', $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display')); + // No settings + $this->assertEquals('', $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value')); + $this->assertEquals($this->lang('NO_ROLE_ASSIGNED'), $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText()); + } +} diff --git a/tests/ui/quick_links_test.php b/tests/ui/quick_links_test.php index 5bddb44a8b..582aeafcae 100644 --- a/tests/ui/quick_links_test.php +++ b/tests/ui/quick_links_test.php @@ -16,7 +16,6 @@ */ class quick_links_test extends phpbb_ui_test_case { - public function test_quick_links() { $this->visit('index.php'); diff --git a/tests/upload/filespec_test.php b/tests/upload/filespec_test.php index ed28bcb38f..1351b46002 100644 --- a/tests/upload/filespec_test.php +++ b/tests/upload/filespec_test.php @@ -13,7 +13,6 @@ require_once __DIR__ . '/../../phpBB/includes/functions.php'; require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php'; -require_once __DIR__ . '/../../phpBB/includes/functions_upload.php'; class phpbb_filespec_test extends phpbb_test_case { @@ -23,14 +22,19 @@ class phpbb_filespec_test extends phpbb_test_case const UPLOAD_MAX_FILESIZE = 1000; private $config; + private $filesystem; public $path; + /** @var \phpbb\language\language */ + protected $language; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + protected function setUp() { // Global $config required by unique_id - // Global $user required by filespec::additional_checks and - // filespec::move_file - global $config, $user; + global $config, $phpbb_root_path, $phpEx; if (!is_array($config)) { @@ -44,9 +48,6 @@ class phpbb_filespec_test extends phpbb_test_case // See: phpBB/install/schemas/schema_data.sql $config['mime_triggers'] = 'body|head|html|img|plaintext|a href|pre|script|table|title'; - $user = new phpbb_mock_user(); - $user->lang = new phpbb_mock_lang(); - $this->config = &$config; $this->path = __DIR__ . '/fixture/'; @@ -75,6 +76,17 @@ class phpbb_filespec_test extends phpbb_test_case $guessers[2]->set_priority(-2); $guessers[3]->set_priority(-2); $this->mimetype_guesser = new \phpbb\mimetype\guesser($guessers); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->phpbb_root_path = $phpbb_root_path; + } + + private function set_reflection_property(&$class, $property_name, $value) + { + $property = new ReflectionProperty($class, $property_name); + $property->setAccessible(true); + $property->setValue($class, $value); } private function get_filespec($override = array()) @@ -88,14 +100,13 @@ class phpbb_filespec_test extends phpbb_test_case 'error' => '', ); - return new filespec(array_merge($upload_ary, $override), null, $this->mimetype_guesser); + $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, new \FastImageSize\FastImageSize(), $this->phpbb_root_path, $this->mimetype_guesser); + return $filespec->set_upload_ary(array_merge($upload_ary, $override)); } protected function tearDown() { - global $user; $this->config = array(); - $user = null; $iterator = new DirectoryIterator($this->path . 'copies'); foreach ($iterator as $fileinfo) @@ -108,6 +119,13 @@ class phpbb_filespec_test extends phpbb_test_case } } + public function test_empty_upload_ary() + { + $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, new \FastImageSize\FastImageSize(), $this->phpbb_root_path, $this->mimetype_guesser); + $this->assertInstanceOf('\phpbb\files\filespec', $filespec->set_upload_ary(array())); + $this->assertTrue($filespec->init_error()); + } + public function additional_checks_variables() { // False here just indicates the file is too large and fails the @@ -129,13 +147,26 @@ class phpbb_filespec_test extends phpbb_test_case { $upload = new phpbb_mock_fileupload(); $filespec = $this->get_filespec(); - $filespec->upload = $upload; - $filespec->file_moved = true; - $filespec->filesize = $filespec->get_filesize($this->path . $filename); + $filespec->set_upload_namespace($upload); + $this->set_reflection_property($filespec, 'file_moved', true); + $this->set_reflection_property($filespec, 'filesize', $filespec->get_filesize($this->path . $filename)); $this->assertEquals($expected, $filespec->additional_checks()); } + public function test_additional_checks_dimensions() + { + $upload = new phpbb_mock_fileupload(); + $filespec = $this->get_filespec(); + $filespec->set_upload_namespace($upload); + $upload->valid_dimensions = false; + $this->set_reflection_property($filespec, 'file_moved', true); + $upload->max_filesize = 0; + + $this->assertEquals(false, $filespec->additional_checks()); + $this->assertSame(array('WRONG_SIZE'), $filespec->error); + } + public function check_content_variables() { // False here indicates that a file is non-binary and contains @@ -170,6 +201,7 @@ class phpbb_filespec_test extends phpbb_test_case array($chunks[2] . $chunks[9]), array($chunks[3] . $chunks[4]), array($chunks[5] . $chunks[6]), + array('foobar.png'), ); } @@ -181,7 +213,7 @@ class phpbb_filespec_test extends phpbb_test_case $bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|'); $filespec = $this->get_filespec(array('name' => $filename)); $filespec->clean_filename('real', self::PREFIX); - $name = $filespec->realname; + $name = $filespec->get('realname'); $this->assertEquals(0, preg_match('/%(\w{2})/', $name)); foreach ($bad_chars as $char) @@ -197,8 +229,8 @@ class phpbb_filespec_test extends phpbb_test_case { $filespec = $this->get_filespec(); $filespec->clean_filename('unique', self::PREFIX); - $name = $filespec->realname; - + $name = $filespec->get('realname'); + $this->assertEquals(strlen($name), 32 + strlen(self::PREFIX)); $this->assertRegExp('#^[A-Za-z0-9]+$#', substr($name, strlen(self::PREFIX))); $this->assertFalse(isset($filenames[$name])); @@ -206,6 +238,55 @@ class phpbb_filespec_test extends phpbb_test_case } } + public function test_clean_filename_unique_ext() + { + $filenames = array(); + for ($tests = 0; $tests < self::TEST_COUNT; $tests++) + { + $filespec = $this->get_filespec(array('name' => 'foobar.jpg')); + $filespec->clean_filename('unique_ext', self::PREFIX); + $name = $filespec->get('realname'); + + $this->assertEquals(strlen($name), 32 + strlen(self::PREFIX) + strlen('.jpg')); + $this->assertRegExp('#^[A-Za-z0-9]+\.jpg$#', substr($name, strlen(self::PREFIX))); + $this->assertFalse(isset($filenames[$name])); + $filenames[$name] = true; + } + } + + public function data_clean_filename_avatar() + { + return array( + array(false, false, ''), + array('foobar.png', 'u5.png', 'avatar', 'u', 5), + array('foobar.png', 'g9.png', 'avatar', 'g', 9), + + ); + } + + /** + * @dataProvider data_clean_filename_avatar + */ + public function test_clean_filename_avatar($filename, $expected, $mode, $prefix = '', $user_id = '') + { + $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, new \FastImageSize\FastImageSize(), $this->phpbb_root_path, $this->mimetype_guesser); + + if ($filename) + { + $upload_ary = array( + 'name' => $filename, + 'type' => '', + 'size' => '', + 'tmp_name' => '', + 'error' => '', + ); + $filespec->set_upload_ary($upload_ary); + } + $filespec->clean_filename($mode, $prefix, $user_id); + + $this->assertSame($expected, $filespec->get('realname')); + } + public function get_extension_variables() { return array( @@ -223,7 +304,7 @@ class phpbb_filespec_test extends phpbb_test_case */ public function test_get_extension($filename, $expected) { - $this->assertEquals($expected, filespec::get_extension($filename)); + $this->assertEquals($expected, \phpbb\files\filespec::get_extension($filename)); } public function is_image_variables() @@ -286,7 +367,7 @@ class phpbb_filespec_test extends phpbb_test_case array('txt_copy', 'txt_as_img', 'image/jpg', 'txt', false, true), array('txt_copy_2', 'txt_moved', 'text/plain', 'txt', false, true), array('jpg_copy', 'jpg_moved', 'image/png', 'jpg', false, true), - array('png_copy', 'png_moved', 'image/png', 'jpg', 'IMAGE_FILETYPE_MISMATCH', true), + array('png_copy', 'png_moved', 'image/png', 'jpg', 'Image file type mismatch: expected extension png but extension jpg given.', true), ); } @@ -297,8 +378,7 @@ class phpbb_filespec_test extends phpbb_test_case { // Global $phpbb_root_path and $phpEx are required by phpbb_chmod global $phpbb_root_path, $phpEx; - $phpbb_root_path = ''; - $phpEx = 'php'; + $this->phpbb_root_path = ''; $upload = new phpbb_mock_fileupload(); $upload->max_filesize = self::UPLOAD_MAX_FILESIZE; @@ -308,18 +388,137 @@ class phpbb_filespec_test extends phpbb_test_case 'name' => $realname, 'type' => $mime_type, )); - $filespec->extension = $extension; - $filespec->upload = $upload; - $filespec->local = true; + $this->set_reflection_property($filespec, 'extension', $extension); + $filespec->set_upload_namespace($upload); + $this->set_reflection_property($filespec, 'local', true); $this->assertEquals($expected, $filespec->move_file($this->path . 'copies')); - $this->assertEquals($filespec->file_moved, file_exists($this->path . 'copies/' . $realname)); + $this->assertEquals($filespec->get('file_moved'), file_exists($this->path . 'copies/' . $realname)); if ($error) { $this->assertEquals($error, $filespec->error[0]); } - $phpEx = ''; + $this->phpbb_root_path = $phpbb_root_path; + } + + public function test_move_file_error() + { + $filespec = $this->get_filespec(); + $this->assertFalse($filespec->move_file('foobar')); + $filespec->error[] = 'foo'; + $this->assertFalse($filespec->move_file('foo')); + } + + public function data_move_file_copy() + { + return array( + array('gif_copy', true, false, array()), + array('gif_copy', true, true, array()), + array('foo_bar', false, false, array('GENERAL_UPLOAD_ERROR')), + array('foo_bar', false, true, array('GENERAL_UPLOAD_ERROR')), + ); + } + + /** + * @dataProvider data_move_file_copy + */ + public function test_move_file_copy($tmp_name, $move_success, $safe_mode_on, $expected_error) + { + // Initialise a blank filespec object for use with trivial methods + $upload_ary = array( + 'name' => 'gif_moved', + 'type' => 'image/gif', + 'size' => '', + 'tmp_name' => $this->path . 'copies/' . $tmp_name, + 'error' => '', + ); + + $php_ini = $this->getMockBuilder('\bantu\IniGetWrapper\IniGetWrapper') + ->getMock(); + $php_ini->expects($this->any()) + ->method('getBool') + ->with($this->anything()) + ->willReturn($safe_mode_on); + $upload = new phpbb_mock_fileupload(); + $upload->max_filesize = self::UPLOAD_MAX_FILESIZE; + $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, $php_ini, new \FastImageSize\FastImagesize, '', $this->mimetype_guesser); + $filespec->set_upload_ary($upload_ary); + $this->set_reflection_property($filespec, 'local', false); + $this->set_reflection_property($filespec, 'extension', 'gif'); + $filespec->set_upload_namespace($upload); + + $this->assertEquals($move_success, $filespec->move_file($this->path . 'copies')); + $this->assertEquals($filespec->get('file_moved'), file_exists($this->path . 'copies/gif_moved')); + $this->assertSame($expected_error, $filespec->error); + } + + public function data_move_file_imagesize() + { + return array( + array( + array( + 'width' => 2, + 'height' => 2, + 'type' => IMAGETYPE_GIF, + ), + array() + ), + array( + array( + 'width' => 2, + 'height' => 2, + 'type' => -1, + ), + array('Image file type -1 for mimetype image/gif not supported.') + ), + array( + array( + 'width' => 0, + 'height' => 0, + 'type' => IMAGETYPE_GIF, + ), + array('The image file you tried to attach is invalid.') + ), + array( + false, + array('It was not possible to determine the dimensions of the image. Please verify that the URL you entered is correct.') + ) + ); + } + + /** + * @dataProvider data_move_file_imagesize + */ + public function test_move_file_imagesize($imagesize_return, $expected_error) + { + // Initialise a blank filespec object for use with trivial methods + $upload_ary = array( + 'name' => 'gif_moved', + 'type' => 'image/gif', + 'size' => '', + 'tmp_name' => $this->path . 'copies/gif_copy', + 'error' => '', + ); + + $imagesize = $this->getMockBuilder('\FastImageSize\FastImageSize') + ->getMock(); + $imagesize->expects($this->any()) + ->method('getImageSize') + ->with($this->anything()) + ->willReturn($imagesize_return); + + $upload = new phpbb_mock_fileupload(); + $upload->max_filesize = self::UPLOAD_MAX_FILESIZE; + $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, $imagesize, '', $this->mimetype_guesser); + $filespec->set_upload_ary($upload_ary); + $this->set_reflection_property($filespec, 'local', false); + $this->set_reflection_property($filespec, 'extension', 'gif'); + $filespec->set_upload_namespace($upload); + + $this->assertEquals(true, $filespec->move_file($this->path . 'copies')); + $this->assertEquals($filespec->get('file_moved'), file_exists($this->path . 'copies/gif_moved')); + $this->assertSame($expected_error, $filespec->error); } /** @@ -333,6 +532,29 @@ class phpbb_filespec_test extends phpbb_test_case $type_cast_helper->set_var($upload_name, $filename, 'string', true, true); $filespec = $this->get_filespec(array('name'=> $upload_name)); - $this->assertSame(trim(utf8_basename(htmlspecialchars($filename))), $filespec->uploadname); + $this->assertSame(trim(utf8_basename(htmlspecialchars($filename))), $filespec->get('uploadname')); + } + + public function test_is_uploaded() + { + $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, new \FastImageSize\FastImageSize(), $this->phpbb_root_path, null); + $reflection_filespec = new ReflectionClass($filespec); + $plupload_property = $reflection_filespec->getProperty('plupload'); + $plupload_property->setAccessible(true); + $plupload_mock = $this->getMockBuilder('\phpbb\plupload\plupload') + ->disableOriginalConstructor() + ->getMock(); + $plupload_mock->expects($this->any()) + ->method('is_active') + ->will($this->returnValue(true)); + $plupload_property->setValue($filespec, $plupload_mock); + $is_uploaded = $reflection_filespec->getMethod('is_uploaded'); + + // Plupload is active and file does not exist + $this->assertFalse($is_uploaded->invoke($filespec)); + + // Plupload is not active and file was not uploaded + $plupload_property->setValue($filespec, null); + $this->assertFalse($is_uploaded->invoke($filespec)); } } diff --git a/tests/upload/fileupload_test.php b/tests/upload/fileupload_test.php index fcfb84125d..05cb8dcf93 100644 --- a/tests/upload/fileupload_test.php +++ b/tests/upload/fileupload_test.php @@ -13,34 +13,88 @@ require_once __DIR__ . '/../../phpBB/includes/functions.php'; require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php'; -require_once __DIR__ . '/../../phpBB/includes/functions_upload.php'; require_once __DIR__ . '/../mock/filespec.php'; class phpbb_fileupload_test extends phpbb_test_case { private $path; + private $filesystem; + + /** @var \Symfony\Component\DependencyInjection\ContainerInterface */ + protected $container; + + /** @var \phpbb\files\factory */ + protected $factory; + + /** @var \bantu\IniGetWrapper\IniGetWrapper */ + protected $php_ini; + + /** @var \phpbb\language\language */ + protected $language; + + /** @var \phpbb\request\request_interface */ + protected $request; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + protected function setUp() { // Global $config required by unique_id - // Global $user required by several functions dealing with translations - // Global $request required by form_upload, local_upload and is_valid - global $config, $user, $request; + global $config, $phpbb_root_path, $phpEx; if (!is_array($config)) { - $config = array(); + $config = new \phpbb\config\config(array()); } $config['rand_seed'] = ''; $config['rand_seed_last_update'] = time() + 600; - $user = new phpbb_mock_user(); - $user->lang = new phpbb_mock_lang(); - - $request = new phpbb_mock_request(); + $this->request = $this->getMock('\phpbb\request\request'); + $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper; + + $this->filesystem = new \phpbb\filesystem\filesystem(); + $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)); + $guessers = array( + new \Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser(), + new \Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser(), + new \phpbb\mimetype\content_guesser(), + new \phpbb\mimetype\extension_guesser(), + ); + $guessers[2]->set_priority(-2); + $guessers[3]->set_priority(-2); + $this->mimetype_guesser = new \phpbb\mimetype\guesser($guessers); + + $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx); + $this->container->set('files.filespec', new \phpbb\files\filespec( + $this->filesystem, + $this->language, + $this->php_ini, + new \FastImageSize\FastImageSize(), + $phpbb_root_path, + new \phpbb\mimetype\guesser(array( + 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(), + )))); + $this->factory = new \phpbb\files\factory($this->container); + $plupload = new \phpbb\plupload\plupload($phpbb_root_path, $config, $this->request, new \phpbb\user($this->language, '\phpbb\datetime'), $this->php_ini, $this->mimetype_guesser); + $this->container->set('files.types.form', new \phpbb\files\types\form( + $this->factory, + $this->language, + $this->php_ini, + $plupload, + $this->request + ), phpbb_mock_container_builder::SCOPE_PROTOTYPE); + $this->container->set('files.types.local', new \phpbb\files\types\local( + $this->factory, + $this->language, + $this->php_ini, + $this->request + ), phpbb_mock_container_builder::SCOPE_PROTOTYPE); $this->path = __DIR__ . '/fixture/'; + $this->phpbb_root_path = $phpbb_root_path; } private function gen_valid_filespec() @@ -65,15 +119,38 @@ class phpbb_fileupload_test extends phpbb_test_case public function test_common_checks_invalid_extension() { - $upload = new fileupload('', array('png'), 100); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('png')) + ->set_max_filesize(100); $file = $this->gen_valid_filespec(); $upload->common_checks($file); $this->assertEquals('DISALLOWED_EXTENSION', $file->error[0]); } + public function test_common_checks_disallowed_content() + { + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('jpg')) + ->set_max_filesize(1000); + $file = new \phpbb\files\filespec($this->filesystem, $this->language, $this->php_ini, new \FastImageSize\FastImageSize(), $this->phpbb_root_path); + $file->set_upload_ary(array( + 'size' => 50, + 'tmp_name' => dirname(__FILE__) . '/fixture/disallowed', + 'name' => 'disallowed.jpg', + 'type' => 'image/jpg' + )) + ->set_upload_namespace($upload); + file_put_contents(dirname(__FILE__) . '/fixture/disallowed', '<body>' . file_get_contents(dirname(__FILE__) . '/fixture/jpg')); + $upload->common_checks($file); + $this->assertEquals('DISALLOWED_CONTENT', $file->error[0]); + unlink(dirname(__FILE__) . '/fixture/disallowed'); + } + public function test_common_checks_invalid_filename() { - $upload = new fileupload('', array('jpg'), 100); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('jpg')) + ->set_max_filesize(100); $file = $this->gen_valid_filespec(); $file->realname = 'invalid?'; $upload->common_checks($file); @@ -82,7 +159,9 @@ class phpbb_fileupload_test extends phpbb_test_case public function test_common_checks_too_large() { - $upload = new fileupload('', array('jpg'), 100); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('jpg')) + ->set_max_filesize(100); $file = $this->gen_valid_filespec(); $file->filesize = 1000; $upload->common_checks($file); @@ -91,7 +170,9 @@ class phpbb_fileupload_test extends phpbb_test_case public function test_common_checks_valid_file() { - $upload = new fileupload('', array('jpg'), 1000); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('jpg')) + ->set_max_filesize(1000); $file = $this->gen_valid_filespec(); $upload->common_checks($file); $this->assertEquals(0, sizeof($file->error)); @@ -99,33 +180,41 @@ class phpbb_fileupload_test extends phpbb_test_case public function test_local_upload() { - $upload = new fileupload('', array('jpg'), 1000); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('jpg')) + ->set_max_filesize(1000); copy($this->path . 'jpg', $this->path . 'jpg.jpg'); - $file = $upload->local_upload($this->path . 'jpg.jpg'); + $file = $upload->handle_upload('files.types.local', $this->path . 'jpg.jpg'); $this->assertEquals(0, sizeof($file->error)); - unlink($this->path . 'jpg.jpg'); + $this->assertFalse($file->additional_checks()); + $this->assertTrue($file->move_file('../tests/upload/fixture/copies', true)); + $file->remove(); } public function test_move_existent_file() { - $upload = new fileupload('', array('jpg'), 1000); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('jpg')) + ->set_max_filesize(1000); copy($this->path . 'jpg', $this->path . 'jpg.jpg'); - $file = $upload->local_upload($this->path . 'jpg.jpg'); + $file = $upload->handle_upload('files.types.local', $this->path . 'jpg.jpg'); $this->assertEquals(0, sizeof($file->error)); $this->assertFalse($file->move_file('../tests/upload/fixture')); - $this->assertFalse($file->file_moved); + $this->assertFalse($file->get('file_moved')); $this->assertEquals(1, sizeof($file->error)); } public function test_move_existent_file_overwrite() { - $upload = new fileupload('', array('jpg'), 1000); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(array('jpg')) + ->set_max_filesize(1000); copy($this->path . 'jpg', $this->path . 'jpg.jpg'); copy($this->path . 'jpg', $this->path . 'copies/jpg.jpg'); - $file = $upload->local_upload($this->path . 'jpg.jpg'); + $file = $upload->handle_upload('files.types.local', $this->path . 'jpg.jpg'); $this->assertEquals(0, sizeof($file->error)); $file->move_file('../tests/upload/fixture/copies', true); $this->assertEquals(0, sizeof($file->error)); @@ -134,7 +223,10 @@ class phpbb_fileupload_test extends phpbb_test_case public function test_valid_dimensions() { - $upload = new fileupload('', false, false, 1, 1, 100, 100); + $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path); + $upload->set_allowed_extensions(false) + ->set_max_filesize(false) + ->set_allowed_dimensions(1, 1, 100, 100); $file1 = $this->gen_valid_filespec(); $file2 = $this->gen_valid_filespec(); diff --git a/tests/upload/fixture/bmp b/tests/upload/fixture/bmp Binary files differnew file mode 100644 index 0000000000..04bff561ab --- /dev/null +++ b/tests/upload/fixture/bmp diff --git a/tests/upload/fixture/iff b/tests/upload/fixture/iff Binary files differnew file mode 100644 index 0000000000..24eda8f593 --- /dev/null +++ b/tests/upload/fixture/iff diff --git a/tests/upload/fixture/iff_maya b/tests/upload/fixture/iff_maya Binary files differnew file mode 100644 index 0000000000..b6fb85101b --- /dev/null +++ b/tests/upload/fixture/iff_maya diff --git a/tests/upload/fixture/jp2 b/tests/upload/fixture/jp2 Binary files differnew file mode 100644 index 0000000000..adca6ecf0e --- /dev/null +++ b/tests/upload/fixture/jp2 diff --git a/tests/upload/fixture/jpx b/tests/upload/fixture/jpx Binary files differnew file mode 100644 index 0000000000..adca6ecf0e --- /dev/null +++ b/tests/upload/fixture/jpx diff --git a/tests/upload/fixture/psd b/tests/upload/fixture/psd Binary files differnew file mode 100644 index 0000000000..d1bc9a6a70 --- /dev/null +++ b/tests/upload/fixture/psd diff --git a/tests/upload/fixture/tif_compressed b/tests/upload/fixture/tif_compressed Binary files differnew file mode 100644 index 0000000000..133b50c4f0 --- /dev/null +++ b/tests/upload/fixture/tif_compressed diff --git a/tests/upload/fixture/tif_msb b/tests/upload/fixture/tif_msb Binary files differnew file mode 100644 index 0000000000..32eb8abfbb --- /dev/null +++ b/tests/upload/fixture/tif_msb diff --git a/tests/upload/fixture/wbmp b/tests/upload/fixture/wbmp Binary files differnew file mode 100644 index 0000000000..708c86ccee --- /dev/null +++ b/tests/upload/fixture/wbmp diff --git a/tests/upload/imagesize_test.php b/tests/upload/imagesize_test.php new file mode 100644 index 0000000000..d20e866dab --- /dev/null +++ b/tests/upload/imagesize_test.php @@ -0,0 +1,99 @@ +<?php + +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +require_once(__DIR__ . '/../../phpBB/includes/functions.php'); + +class phpbb_upload_imagesize_test extends \phpbb_test_case +{ + /** @var \FastImageSize\FastImageSize */ + protected $imagesize; + + /** @var string Path to fixtures */ + protected $path; + + public function setUp() + { + parent::setUp(); + $this->imagesize = new \FastImageSize\FastImageSize(); + $this->path = __DIR__ . '/fixture/'; + } + + public function data_get_imagesize() + { + return array( + array('foobar', 'image/bmp', false), + array('png', 'image/png', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_PNG)), + array('gif', 'image/png', false), + array('png', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_PNG)), + array('gif', 'image/gif', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_GIF)), + array('jpg', 'image/gif', false), + array('gif', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_GIF)), + array('jpg', 'image/jpg', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)), + array('jpg', 'image/jpeg', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)), + array('png', 'image/jpg', false), + array('jpg', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)), + array('psd', 'image/psd', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)), + array('psd', 'image/photoshop', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)), + array('jpg', 'image/psd', false), + array('psd', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)), + array('bmp', 'image/bmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_BMP)), + array('png', 'image/bmp', false), + array('bmp', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_BMP)), + array('tif', 'image/tif', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)), + array('png', 'image/tif', false), + array('tif', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)), + array('tif_compressed', 'image/tif', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)), + array('png', 'image/tiff', false), + array('tif_compressed', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)), + array('tif_msb', 'image/tif', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_MM)), + array('tif_msb', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_MM)), + array('wbmp', 'image/wbmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)), + array('wbmp', 'image/vnd.wap.wbmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)), + array('png', 'image/vnd.wap.wbmp', false), + array('wbmp', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)), + array('iff', 'image/iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('iff', 'image/x-iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('iff_maya', 'iamge/iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('png', 'image/iff', false), + array('png', 'image/x-iff', false), + array('iff', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('iff_maya', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)), + array('jp2', 'image/jp2', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jp2', 'image/jpx', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jp2', 'image/jpm', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jpg', 'image/jp2', false), + array('jpx', 'image/jpx', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jp2', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + array('jpx', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)), + ); + } + + /** + * @dataProvider data_get_imagesize + */ + public function test_get_imagesize($file, $mime_type, $expected) + { + $this->assertEquals($expected, $this->imagesize->getImageSize($this->path . $file, $mime_type)); + } + + public function test_get_imagesize_remote() + { + $this->assertSame(array( + 'width' => 80, + 'height' => 80, + 'type' => IMAGETYPE_JPEG, + ), + $this->imagesize->getImageSize('https://secure.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0.jpg')); + } +} diff --git a/tests/user/lang_test.php b/tests/user/lang_test.php deleted file mode 100644 index bb11bb63cb..0000000000 --- a/tests/user/lang_test.php +++ /dev/null @@ -1,119 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; - -class phpbb_user_lang_test extends phpbb_test_case -{ - public function test_user_lang_sprintf() - { - $user = new \phpbb\user('\phpbb\datetime'); - $user->lang = array( - 'FOO' => 'BAR', - 'BARZ' => 'PENG', - 'EMPTY' => '', - 'ZERO' => '0', - 'STR' => '%d %s, %d topics', - 'STR2' => '%d foos', - 'ARRY' => array( - 0 => 'No posts', // 0 - 1 => '1 post', // 1 - 2 => '%d posts', // 2+ - ), - 'ARRY_NO_ZERO' => array( - 1 => '1 post', // 1 - 2 => '%d posts', // 0, 2+ - ), - 'ARRY_MISSING' => array( - 1 => '%d post', // 1 - //Missing second plural - ), - 'ARRY_FLOAT' => array( - 1 => '1 post', // 1.x - 2 => '%1$.1f posts', // 0.x, 2+.x - ), - 'ARRY_EMPTY' => array( - ), - 'dateformat' => array( - 'AGO' => array( - 1 => '%d second', - 2 => '%d seconds', - ), - ), - ); - - // No param - $this->assertEquals($user->lang('FOO'), 'BAR'); - $this->assertEquals($user->lang('EMPTY'), ''); - $this->assertEquals($user->lang('ZERO'), '0'); - - // Invalid index - $this->assertEquals($user->lang('VOID'), 'VOID'); - - // Unnecessary param - $this->assertEquals($user->lang('FOO', 2), 'BAR'); - $this->assertEquals($user->lang('FOO', 2, 3), 'BAR'); - $this->assertEquals($user->lang('FOO', 2, 3, 'BARZ'), 'BAR'); - - // String - $this->assertEquals($user->lang('STR', 24, 'x', 42), '24 x, 42 topics'); - $this->assertEquals($user->lang('STR2', 64), '64 foos'); - - // Array - $this->assertEquals($user->lang('ARRY', 0), 'No posts'); - $this->assertEquals($user->lang('ARRY', 1), '1 post'); - $this->assertEquals($user->lang('ARRY', 2), '2 posts'); - $this->assertEquals($user->lang('ARRY', 123), '123 posts'); - - // Empty array returns the language key - $this->assertEquals($user->lang('ARRY_EMPTY', 123), 'ARRY_EMPTY'); - - // No 0 key defined - $this->assertEquals($user->lang('ARRY_NO_ZERO', 0), '0 posts'); - $this->assertEquals($user->lang('ARRY_NO_ZERO', 1), '1 post'); - $this->assertEquals($user->lang('ARRY_NO_ZERO', 2), '2 posts'); - - // Array with missing keys - $this->assertEquals($user->lang('ARRY_MISSING', 2), '2 post'); - - // Floats as array key - $this->assertEquals($user->lang('ARRY_FLOAT', 1.3), '1 post'); - $this->assertEquals($user->lang('ARRY_FLOAT', 2.0), '2.0 posts'); - $this->assertEquals($user->lang('ARRY_FLOAT', 2.51), '2.5 posts'); - - // Use sub key, if first paramenter is an array - $this->assertEquals($user->lang(array('dateformat', 'AGO'), 2), '2 seconds'); - - // ticket PHPBB3-9949 - use first int to determinate the plural-form to use - $this->assertEquals($user->lang('ARRY', 1, 2), '1 post'); - $this->assertEquals($user->lang('ARRY', 1, 's', 2), '1 post'); - - // ticket PHPBB3-10345 - different plural rules, not just 0/1/2+ - $user = new \phpbb\user('\phpbb\datetime'); - $user->lang = array( - 'PLURAL_RULE' => 13, - 'ARRY' => array( - 0 => '%d is 0', // 0 - 1 => '%d is 1', // 1 - 2 => '%d ends with 01-10', // ending with 01-10 - 3 => '%d ends with 11-19', // ending with 11-19 - 4 => '%d is part of the last rule', // everything else - ), - ); - $this->assertEquals($user->lang('ARRY', 0), '0 is 0'); - $this->assertEquals($user->lang('ARRY', 1), '1 is 1'); - $this->assertEquals($user->lang('ARRY', 103), '103 ends with 01-10'); - $this->assertEquals($user->lang('ARRY', 15), '15 ends with 11-19'); - $this->assertEquals($user->lang('ARRY', 300), '300 is part of the last rule'); - } -} diff --git a/tests/utf/normalizer_test.php b/tests/utf/normalizer_test.php deleted file mode 100644 index 50eafda859..0000000000 --- a/tests/utf/normalizer_test.php +++ /dev/null @@ -1,327 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_normalizer.php'; - -/** -* @group slow -*/ -class phpbb_utf_normalizer_test extends phpbb_test_case -{ - static private $data_dir; - - static public function setUpBeforeClass() - { - self::$data_dir = dirname(__file__) . '/../tmp'; - self::download('http://www.unicode.org/Public/UNIDATA/NormalizationTest.txt', self::$data_dir); - self::download('http://www.unicode.org/Public/UNIDATA/UnicodeData.txt', self::$data_dir); - } - - public function test_normalizer() - { - $test_suite = array( - /** - * NFC - * c2 == NFC(c1) == NFC(c2) == NFC(c3) - * c4 == NFC(c4) == NFC(c5) - */ - 'NFC' => array( - 'c2' => array('c1', 'c2', 'c3'), - 'c4' => array('c4', 'c5') - ), - - /** - * NFD - * c3 == NFD(c1) == NFD(c2) == NFD(c3) - * c5 == NFD(c4) == NFD(c5) - */ - 'NFD' => array( - 'c3' => array('c1', 'c2', 'c3'), - 'c5' => array('c4', 'c5') - ), - - /** - * NFKC - * c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) - */ - 'NFKC' => array( - 'c4' => array('c1', 'c2', 'c3', 'c4', 'c5') - ), - - /** - * NFKD - * c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) - */ - 'NFKD' => array( - 'c5' => array('c1', 'c2', 'c3', 'c4', 'c5') - ) - ); - - $tested_chars = array(); - - $fp = fopen(self::$data_dir . '/NormalizationTest.txt', 'rb'); - while (!feof($fp)) - { - $line = fgets($fp); - - if ($line[0] == '@') - { - continue; - } - - if (!strpos(' 0123456789ABCDEF', $line[0])) - { - continue; - } - - list($c1, $c2, $c3, $c4, $c5) = explode(';', $line); - - if (!strpos($c1, ' ')) - { - /** - * We are currently testing a single character, we add it to the list of - * characters we have processed so that we can exclude it when testing - * for invariants - */ - $tested_chars[$c1] = 1; - } - - foreach ($test_suite as $form => $serie) - { - foreach ($serie as $expected => $tests) - { - $hex_expected = ${$expected}; - $utf_expected = $this->hexseq_to_utf($hex_expected); - - foreach ($tests as $test) - { - $utf_result = $utf_expected; - call_user_func_array(array('utf_normalizer', $form), array(&$utf_result)); - - $hex_result = $this->utf_to_hexseq($utf_result); - $this->assertEquals($utf_expected, $utf_result, "$expected == $form($test) ($hex_expected != $hex_result)"); - } - } - } - } - fclose($fp); - - return $tested_chars; - } - - /** - * @depends test_normalizer - */ - public function test_invariants(array $tested_chars) - { - $fp = fopen(self::$data_dir . '/UnicodeData.txt', 'rb'); - - while (!feof($fp)) - { - $line = fgets($fp, 1024); - - if (!$pos = strpos($line, ';')) - { - continue; - } - - $hex_tested = $hex_expected = substr($line, 0, $pos); - - if (isset($tested_chars[$hex_tested])) - { - continue; - } - - $utf_expected = $this->hex_to_utf($hex_expected); - - if ($utf_expected >= UTF8_SURROGATE_FIRST - && $utf_expected <= UTF8_SURROGATE_LAST) - { - /** - * Surrogates are illegal on their own, we expect the normalizer - * to return a replacement char - */ - $utf_expected = UTF8_REPLACEMENT; - $hex_expected = $this->utf_to_hexseq($utf_expected); - } - - foreach (array('nfc', 'nfkc', 'nfd', 'nfkd') as $form) - { - $utf_result = $utf_expected; - call_user_func_array(array('utf_normalizer', $form), array(&$utf_result)); - $hex_result = $this->utf_to_hexseq($utf_result); - - $this->assertEquals($utf_expected, $utf_result, "$hex_expected == $form($hex_tested) ($hex_expected != $hex_result)"); - } - } - fclose($fp); - } - - /** - * Convert a UTF string to a sequence of codepoints in hexadecimal - * - * @param string $utf UTF string - * @return integer Unicode codepoints in hex - */ - protected function utf_to_hexseq($str) - { - $pos = 0; - $len = strlen($str); - $ret = array(); - - while ($pos < $len) - { - $c = $str[$pos]; - switch ($c & "\xF0") - { - case "\xC0": - case "\xD0": - $utf_char = substr($str, $pos, 2); - $pos += 2; - break; - - case "\xE0": - $utf_char = substr($str, $pos, 3); - $pos += 3; - break; - - case "\xF0": - $utf_char = substr($str, $pos, 4); - $pos += 4; - break; - - default: - $utf_char = $c; - ++$pos; - } - - $hex = dechex($this->utf_to_cp($utf_char)); - - if (!isset($hex[3])) - { - $hex = substr('000' . $hex, -4); - } - - $ret[] = $hex; - } - - return strtr(implode(' ', $ret), 'abcdef', 'ABCDEF'); - } - - /** - * Convert a UTF-8 char to its codepoint - * - * @param string $utf_char UTF-8 char - * @return integer Unicode codepoint - */ - protected function utf_to_cp($utf_char) - { - switch (strlen($utf_char)) - { - case 1: - return ord($utf_char); - - case 2: - return ((ord($utf_char[0]) & 0x1F) << 6) | (ord($utf_char[1]) & 0x3F); - - case 3: - return ((ord($utf_char[0]) & 0x0F) << 12) | ((ord($utf_char[1]) & 0x3F) << 6) | (ord($utf_char[2]) & 0x3F); - - case 4: - return ((ord($utf_char[0]) & 0x07) << 18) | ((ord($utf_char[1]) & 0x3F) << 12) | ((ord($utf_char[2]) & 0x3F) << 6) | (ord($utf_char[3]) & 0x3F); - - default: - throw new RuntimeException('UTF-8 chars can only be 1-4 bytes long'); - } - } - - /** - * Return a UTF string formed from a sequence of codepoints in hexadecimal - * - * @param string $seq Sequence of codepoints, separated with a space - * @return string UTF-8 string - */ - protected function hexseq_to_utf($seq) - { - return implode('', array_map(array($this, 'hex_to_utf'), explode(' ', $seq))); - } - - /** - * Convert a codepoint in hexadecimal to a UTF-8 char - * - * @param string $hex Codepoint, in hexadecimal - * @return string UTF-8 char - */ - protected function hex_to_utf($hex) - { - return $this->cp_to_utf(hexdec($hex)); - } - - /** - * Convert a codepoint to a UTF-8 char - * - * @param integer $cp Unicode codepoint - * @return string UTF-8 string - */ - protected function cp_to_utf($cp) - { - if ($cp > 0xFFFF) - { - return chr(0xF0 | ($cp >> 18)) . chr(0x80 | (($cp >> 12) & 0x3F)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F)); - } - else if ($cp > 0x7FF) - { - return chr(0xE0 | ($cp >> 12)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F)); - } - else if ($cp > 0x7F) - { - return chr(0xC0 | ($cp >> 6)) . chr(0x80 | ($cp & 0x3F)); - } - else - { - return chr($cp); - } - } - - // chunked download helper - static protected function download($url, $to) - { - $target = $to . '/' . basename($url); - - if (file_exists($target)) - { - return; - } - - if (!$fpr = fopen($url, 'rb')) - { - echo "Failed to download $url\n"; - return; - } - - if (!$fpw = fopen($target, 'wb')) - { - echo "Failed to open $target for writing\n"; - return; - } - - $chunk = 32768; - - while (!feof($fpr)) - { - fwrite($fpw, fread($fpr, $chunk)); - } - fclose($fpr); - fclose($fpw); - } -} diff --git a/tests/version/version_fetch_test.php b/tests/version/version_fetch_test.php index cfc87183cf..6ecc9b7223 100644 --- a/tests/version/version_fetch_test.php +++ b/tests/version/version_fetch_test.php @@ -28,13 +28,15 @@ class phpbb_version_helper_fetch_test extends phpbb_test_case ->disableOriginalConstructor() ->getMock(); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $this->version_helper = new \phpbb\version_helper( $this->cache, new \phpbb\config\config(array( 'version' => '3.1.0', )), new \phpbb\file_downloader(), - new \phpbb\user('\phpbb\datetime') + new \phpbb\user(new \phpbb\language\language($lang_loader), '\phpbb\datetime') ); } diff --git a/tests/version/version_helper_remote_test.php b/tests/version/version_helper_remote_test.php index 65ae7646b9..724c4c970c 100644 --- a/tests/version/version_helper_remote_test.php +++ b/tests/version/version_helper_remote_test.php @@ -30,20 +30,22 @@ class version_helper_remote_test extends \phpbb_test_case )); $container = new \phpbb_mock_container_builder(); $db = new \phpbb\db\driver\factory($container); - $this->cache = $this->getMock('\phpbb\cache\service', array('get'), array(new \phpbb\cache\driver\null(), $config, $db, '../../', 'php')); + $this->cache = $this->getMock('\phpbb\cache\service', array('get'), array(new \phpbb\cache\driver\dummy(), $config, $db, '../../', 'php')); $this->cache->expects($this->any()) ->method('get') ->with($this->anything()) ->will($this->returnValue(false)); $this->file_downloader = new phpbb_mock_file_downloader(); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $this->version_helper = new \phpbb\version_helper( $this->cache, $config, $this->file_downloader, - new \phpbb\user('\phpbb\datetime') + new \phpbb\user(new \phpbb\language\language($lang_loader), '\phpbb\datetime') ); - $this->user = new \phpbb\user('\phpbb\datetime'); + $this->user = new \phpbb\user(new \phpbb\language\language($lang_loader), '\phpbb\datetime'); $this->user->add_lang('acp/common'); } diff --git a/tests/version/version_test.php b/tests/version/version_test.php index 528f1602d6..05577f6a18 100644 --- a/tests/version/version_test.php +++ b/tests/version/version_test.php @@ -25,13 +25,15 @@ class phpbb_version_helper_test extends phpbb_test_case ->disableOriginalConstructor() ->getMock(); + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $this->version_helper = new \phpbb\version_helper( $this->cache, new \phpbb\config\config(array( 'version' => '3.1.0', )), new \phpbb\file_downloader(), - new \phpbb\user('\phpbb\datetime') + new \phpbb\user(new \phpbb\language\language($lang_loader), '\phpbb\datetime') ); } @@ -199,6 +201,11 @@ class phpbb_version_helper_test extends phpbb_test_case */ public function test_get_suggested_updates($current_version, $versions, $expected) { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $version_helper = $this ->getMockBuilder('\phpbb\version_helper') ->setMethods(array( @@ -210,7 +217,7 @@ class phpbb_version_helper_test extends phpbb_test_case 'version' => $current_version, )), new \phpbb\file_downloader(), - new \phpbb\user('\phpbb\datetime'), + new \phpbb\user($lang, '\phpbb\datetime'), )) ->getMock() ; @@ -310,6 +317,11 @@ class phpbb_version_helper_test extends phpbb_test_case */ public function test_get_latest_on_current_branch($current_version, $versions, $expected) { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $version_helper = $this ->getMockBuilder('\phpbb\version_helper') ->setMethods(array( @@ -321,7 +333,7 @@ class phpbb_version_helper_test extends phpbb_test_case 'version' => $current_version, )), new \phpbb\file_downloader(), - new \phpbb\user('\phpbb\datetime'), + new \phpbb\user($lang, '\phpbb\datetime'), )) ->getMock() ; diff --git a/tests/viewonline/helper_test.php b/tests/viewonline/helper_test.php index bbbed59de7..6540d33287 100644 --- a/tests/viewonline/helper_test.php +++ b/tests/viewonline/helper_test.php @@ -17,7 +17,7 @@ class phpbb_viewonline_helper_test extends phpbb_test_case { parent::setUp(); - $this->viewonline_helper = new \phpbb\viewonline_helper(new \phpbb\filesystem()); + $this->viewonline_helper = new \phpbb\viewonline_helper(new \phpbb\filesystem\filesystem()); } public function session_pages_data() diff --git a/tests/wrapper/phpbb_php_ini_fake.php b/tests/wrapper/phpbb_php_ini_fake.php index f218ff6d03..300ce30cfe 100644 --- a/tests/wrapper/phpbb_php_ini_fake.php +++ b/tests/wrapper/phpbb_php_ini_fake.php @@ -11,7 +11,7 @@ * */ -class phpbb_php_ini_fake extends \phpbb\php\ini +class phpbb_php_ini_fake extends \bantu\IniGetWrapper\IniGetWrapper { function get($varname) { diff --git a/tests/wrapper/phpbb_php_ini_test.php b/tests/wrapper/phpbb_php_ini_test.php index 27c2487f0a..9f46a78d5b 100644 --- a/tests/wrapper/phpbb_php_ini_test.php +++ b/tests/wrapper/phpbb_php_ini_test.php @@ -16,6 +16,7 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; class phpbb_wrapper_phpbb_php_ini_test extends phpbb_test_case { + /** @var \phpbb_php_ini_fake php_ini */ protected $php_ini; public function setUp() @@ -25,44 +26,44 @@ class phpbb_wrapper_phpbb_php_ini_test extends phpbb_test_case public function test_get_string() { - $this->assertSame(false, $this->php_ini->get_string(false)); - $this->assertSame('phpbb', $this->php_ini->get_string(' phpbb ')); + $this->assertSame('', $this->php_ini->getString(false)); + $this->assertSame('phpbb', $this->php_ini->getString(' phpbb ')); } public function test_get_bool() { - $this->assertSame(true, $this->php_ini->get_bool('ON')); - $this->assertSame(true, $this->php_ini->get_bool('on')); - $this->assertSame(true, $this->php_ini->get_bool('1')); + $this->assertSame(true, $this->php_ini->getBool('ON')); + $this->assertSame(true, $this->php_ini->getBool('on')); + $this->assertSame(true, $this->php_ini->getBool('1')); - $this->assertSame(false, $this->php_ini->get_bool('OFF')); - $this->assertSame(false, $this->php_ini->get_bool('off')); - $this->assertSame(false, $this->php_ini->get_bool('0')); - $this->assertSame(false, $this->php_ini->get_bool('')); + $this->assertSame(false, $this->php_ini->getBool('OFF')); + $this->assertSame(false, $this->php_ini->getBool('off')); + $this->assertSame(false, $this->php_ini->getBool('0')); + $this->assertSame(false, $this->php_ini->getBool('')); } public function test_get_int() { - $this->assertSame(1234, $this->php_ini->get_int('1234')); - $this->assertSame(-12345, $this->php_ini->get_int('-12345')); - $this->assertSame(false, $this->php_ini->get_int('phpBB')); + $this->assertSame(1234, $this->php_ini->getNumeric('1234')); + $this->assertSame(-12345, $this->php_ini->getNumeric('-12345')); + $this->assertSame(null, $this->php_ini->getNumeric('phpBB')); } public function test_get_float() { - $this->assertSame(1234.0, $this->php_ini->get_float('1234')); - $this->assertSame(-12345.0, $this->php_ini->get_float('-12345')); - $this->assertSame(false, $this->php_ini->get_float('phpBB')); + $this->assertSame(1234.0, $this->php_ini->getNumeric('1234.0')); + $this->assertSame(-12345.0, $this->php_ini->getNumeric('-12345.0')); + $this->assertSame(null, $this->php_ini->getNumeric('phpBB')); } public function test_get_bytes_invalid() { - $this->assertSame(false, $this->php_ini->get_bytes(false)); - $this->assertSame(false, $this->php_ini->get_bytes('phpBB')); - $this->assertSame(false, $this->php_ini->get_bytes('k')); - $this->assertSame(false, $this->php_ini->get_bytes('-k')); - $this->assertSame(false, $this->php_ini->get_bytes('M')); - $this->assertSame(false, $this->php_ini->get_bytes('-M')); + $this->assertSame(null, $this->php_ini->getBytes(false)); + $this->assertSame(null, $this->php_ini->getBytes('phpBB')); + $this->assertSame(null, $this->php_ini->getBytes('k')); + $this->assertSame(null, $this->php_ini->getBytes('-k')); + $this->assertSame(null, $this->php_ini->getBytes('M')); + $this->assertSame(null, $this->php_ini->getBytes('-M')); } /** @@ -70,7 +71,7 @@ class phpbb_wrapper_phpbb_php_ini_test extends phpbb_test_case */ public function test_get_bytes($expected, $value) { - $actual = $this->php_ini->get_bytes($value); + $actual = $this->php_ini->getBytes($value); $this->assertTrue(is_float($actual) || is_int($actual)); $this->assertEquals($expected, $actual); |