aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/attachment/delete_test.php127
-rw-r--r--tests/attachment/fixtures/resync.xml130
-rw-r--r--tests/attachment/manager_test.php131
-rw-r--r--tests/attachment/resync_test.php74
-rw-r--r--tests/attachment/upload_test.php430
-rw-r--r--tests/auth/provider_oauth_token_storage_test.php8
-rw-r--r--tests/avatar/manager_test.php13
-rw-r--r--tests/bootstrap.php2
-rw-r--r--tests/cache/apc_driver_test.php6
-rw-r--r--tests/console/cron/run_test.php8
-rw-r--r--tests/console/fixtures/png.pngbin0 -> 129 bytes
-rw-r--r--tests/console/fixtures/thumbnail.xml40
-rw-r--r--tests/console/fixtures/txt.txt2
-rw-r--r--tests/console/thumbnail_test.php125
-rw-r--r--tests/content_visibility/delete_post_test.php3
-rw-r--r--tests/controller/common_helper_route.php55
-rw-r--r--tests/controller/controller_test.php14
-rw-r--r--tests/controller/ext/vendor2/foo/config/routing.yml4
-rw-r--r--tests/dbal/boolean_processor_test.php324
-rw-r--r--tests/dbal/fixtures/boolean_processor.xml84
-rw-r--r--tests/dbal/fixtures/migrator_permission.xml134
-rw-r--r--tests/dbal/migrator_tool_module_test.php5
-rw-r--r--tests/dbal/migrator_tool_permission_test.php62
-rw-r--r--tests/di/create_container_test.php89
-rw-r--r--tests/di/fixtures/config.php2
-rw-r--r--tests/di/fixtures/config/production/config.yml2
-rw-r--r--tests/di/fixtures/config/production/container/environment.yml29
-rw-r--r--tests/di/fixtures/other_config/production/config.yml2
-rw-r--r--tests/di/fixtures/other_config/production/container/environment.yml29
-rw-r--r--tests/di/ordered_service_collection_test.php51
-rw-r--r--tests/di/service_collection_test.php47
-rw-r--r--tests/event/exception_listener_test.php4
-rw-r--r--tests/event/fixtures/adm/style/acp_bbcodes.html0
-rw-r--r--tests/event/fixtures/normal_events.md.test20
-rw-r--r--tests/event/md_exporter_test.php92
-rw-r--r--tests/extension/modules_test.php51
-rw-r--r--tests/files/type_foo.php31
-rw-r--r--tests/files/types_base_test.php93
-rw-r--r--tests/files/types_form_test.php174
-rw-r--r--tests/files/types_local_test.php163
-rw-r--r--tests/files/types_remote_test.php141
-rw-r--r--tests/files/upload_test.php128
-rw-r--r--tests/functional/browse_test.php14
-rw-r--r--tests/functional/controllers_compatibility_test.php13
-rw-r--r--tests/functional/extension_acp_test.php2
-rw-r--r--tests/functional/extension_global_lang_test.php7
-rw-r--r--tests/functional/extension_module_test.php11
-rw-r--r--tests/functional/feed_test.php141
-rw-r--r--tests/functional/fileupload_remote_test.php68
-rw-r--r--tests/functional/forum_style_test.php24
-rw-r--r--tests/functional/metadata_manager_test.php7
-rw-r--r--tests/functional/notification_test.php10
-rw-r--r--tests/functional/plupload_test.php1
-rw-r--r--tests/functional/posting_test.php92
-rw-r--r--tests/functional/private_messages_test.php41
-rw-r--r--tests/functional/search/base.php7
-rw-r--r--tests/functions/fixtures/user_delete.xml46
-rw-r--r--tests/functions/user_delete_test.php114
-rw-r--r--tests/functions_acp/build_cfg_template_test.php2
-rw-r--r--tests/functions_install/ignore_new_file_on_update_test.php45
-rw-r--r--tests/functions_privmsgs/fixtures/get_max_setting_from_group.xml83
-rw-r--r--tests/functions_privmsgs/get_max_setting_from_group_test.php64
-rw-r--r--tests/functions_user/delete_user_test.php14
-rw-r--r--tests/group/helper_test.php68
-rw-r--r--tests/help/manager_test.php184
-rw-r--r--tests/installer/database_helper_test.php157
-rw-r--r--tests/installer/installer_config_test.php79
-rw-r--r--tests/installer/mocks/test_installer_module.php20
-rw-r--r--tests/installer/mocks/test_installer_task_mock.php44
-rw-r--r--tests/installer/module_base_test.php65
-rw-r--r--tests/installer/navigation_provider_test.php34
-rw-r--r--tests/language/language_test.php14
-rw-r--r--tests/lint_test.php2
-rw-r--r--tests/log/add_test.php9
-rw-r--r--tests/log/fixtures/delete_log.xml16
-rw-r--r--tests/log/fixtures/empty_log.xml1
-rw-r--r--tests/log/fixtures/full_log.xml12
-rw-r--r--tests/log/function_view_log_test.php16
-rw-r--r--tests/mock/container_builder.php15
-rw-r--r--tests/mock/controller_helper.php13
-rw-r--r--tests/mock/fileupload.php3
-rw-r--r--tests/mock/notification_manager.php7
-rw-r--r--tests/mock/notification_type_post.php6
-rw-r--r--tests/notification/base.php65
-rw-r--r--tests/notification/ext/test/notification/type/test.php5
-rw-r--r--tests/notification/fixtures/services_notification.yml76
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.bookmark.xml10
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.post.xml14
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml14
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.quote.xml10
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.topic.xml8
-rw-r--r--tests/notification/group_request_test.php5
-rw-r--r--tests/notification/manager_helper.php36
-rw-r--r--tests/notification/notification_test.php50
-rw-r--r--tests/notification/submit_post_base.php70
-rw-r--r--tests/notification/submit_post_type_quote_test.php3
-rw-r--r--tests/notification/user_list_trim_test.php4
-rw-r--r--tests/pagination/pagination_test.php12
-rw-r--r--tests/plupload/plupload_test.php2
-rw-r--r--tests/privmsgs/delete_user_pms_test.php4
-rw-r--r--tests/search/mysql_test.php3
-rw-r--r--tests/search/native_test.php3
-rw-r--r--tests/search/postgres_test.php3
-rw-r--r--tests/template/template_includecss_test.php8
-rw-r--r--tests/test_framework/mock/phpbb_mock_null_installer_task.php30
-rw-r--r--tests/test_framework/phpbb_database_test_connection_manager.php8
-rw-r--r--tests/test_framework/phpbb_functional_test_case.php211
-rw-r--r--tests/test_framework/phpbb_test_case_helpers.php111
-rw-r--r--tests/test_framework/phpbb_ui_test_case.php160
-rw-r--r--tests/text_formatter/s9e/default_formatting_test.php107
-rw-r--r--tests/text_formatter/s9e/factory_test.php18
-rw-r--r--tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html2
-rw-r--r--tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html2
-rw-r--r--tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html2
-rw-r--r--tests/text_formatter/s9e/renderer_test.php4
-rw-r--r--tests/text_formatter/s9e/utils_test.php128
-rw-r--r--tests/text_processing/decode_message_test.php8
-rw-r--r--tests/text_processing/generate_text_for_display_test.php2
-rw-r--r--tests/text_processing/message_parser_test.php53
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10587.html4
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10587.txt4
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10922.html10
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10922.txt10
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10989.html2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-11742.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-11742.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-12195.html2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-12221.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-12221.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13451.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13451.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13921.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13921.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13921.xml28
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14405.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14405.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9791.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9791.txt1
-rw-r--r--tests/text_reparser/fixtures/config_text.xml7
-rw-r--r--tests/text_reparser/manager_test.php117
-rw-r--r--tests/text_reparser/plugins/contact_admin_info_test.php96
-rw-r--r--tests/text_reparser/plugins/fixtures/contact_admin_info.xml23
-rw-r--r--tests/text_reparser/plugins/fixtures/forums.xml113
-rw-r--r--tests/text_reparser/plugins/fixtures/groups.xml69
-rw-r--r--tests/text_reparser/plugins/fixtures/poll_options.xml133
-rw-r--r--tests/text_reparser/plugins/fixtures/polls.xml98
-rw-r--r--tests/text_reparser/plugins/fixtures/posts.xml91
-rw-r--r--tests/text_reparser/plugins/fixtures/privmsgs.xml113
-rw-r--r--tests/text_reparser/plugins/fixtures/users.xml91
-rw-r--r--tests/text_reparser/plugins/forum_description_test.php26
-rw-r--r--tests/text_reparser/plugins/forum_rules_test.php26
-rw-r--r--tests/text_reparser/plugins/group_description_test.php26
-rw-r--r--tests/text_reparser/plugins/pm_text_test.php26
-rw-r--r--tests/text_reparser/plugins/poll_option_test.php130
-rw-r--r--tests/text_reparser/plugins/poll_title_test.php26
-rw-r--r--tests/text_reparser/plugins/post_text_test.php26
-rw-r--r--tests/text_reparser/plugins/test_row_based_plugin.php151
-rw-r--r--tests/text_reparser/plugins/user_signature_test.php26
-rw-r--r--tests/upload/filespec_test.php271
-rw-r--r--tests/upload/fileupload_test.php136
-rw-r--r--tests/upload/imagesize_test.php4
-rw-r--r--tests/wrapper/phpbb_php_ini_fake.php2
-rw-r--r--tests/wrapper/phpbb_php_ini_test.php45
163 files changed, 6896 insertions, 799 deletions
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_oauth_token_storage_test.php b/tests/auth/provider_oauth_token_storage_test.php
index 78b936ee8e..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()
@@ -36,6 +37,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c
$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';
@@ -44,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()
@@ -98,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);
@@ -129,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/manager_test.php b/tests/avatar/manager_test.php
index 71f40c0b13..924f1319a2 100644
--- a/tests/avatar/manager_test.php
+++ b/tests/avatar/manager_test.php
@@ -57,7 +57,9 @@ 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();
+ $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, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache));
@@ -65,12 +67,17 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
->method('get_name')
->will($this->returnValue('avatar.driver.foobar'));
// barfoo driver can't be mocked with constructor arguments
- $this->avatar_barfoo = $this->getMock('\phpbb\avatar\driver\barfoo', array('get_name'));
+ $this->avatar_barfoo = $this->getMock('\phpbb\avatar\driver\barfoo', array('get_name', 'get_config_name'));
$this->avatar_barfoo->expects($this->any())
->method('get_name')
->will($this->returnValue('avatar.driver.barfoo'));
+ $this->avatar_barfoo->expects($this->any())
+ ->method('get_config_name')
+ ->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')
@@ -79,7 +86,7 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
}
else
{
- $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $filesystem, $path_helper, $guesser, $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')
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index ace48ea035..86e1e5314b 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -16,6 +16,8 @@ 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/console/cron/run_test.php b/tests/console/cron/run_test.php
index 51ea49b282..d6c7b21781 100644
--- a/tests/console/cron/run_test.php
+++ b/tests/console/cron/run_test.php
@@ -78,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();
@@ -126,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
new file mode 100644
index 0000000000..c143a26a06
--- /dev/null
+++ b/tests/console/fixtures/png.png
Binary files differ
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 b59b6493d4..ba0a21a1a4 100644
--- a/tests/content_visibility/delete_post_test.php
+++ b/tests/content_visibility/delete_post_test.php
@@ -312,12 +312,15 @@ class phpbb_content_visibility_delete_post_test extends phpbb_database_test_case
$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, $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/controller/common_helper_route.php b/tests/controller/common_helper_route.php
index 44e5e12ab0..72c5328b0b 100644
--- a/tests/controller/common_helper_route.php
+++ b/tests/controller/common_helper_route.php
@@ -89,6 +89,7 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
$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, '');
@@ -121,9 +122,12 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
)
);
- $this->router = new phpbb_mock_router($this->filesystem, dirname(__FILE__) . '/', 'php', PHPBB_ENVIRONMENT, $this->extension_manager);
- $this->router->find_routing_files($this->extension_manager->all_enabled(false));
- $this->router->find(dirname(__FILE__) . '/');
+ $loader = new \Symfony\Component\Routing\Loader\YamlFileLoader(
+ new \phpbb\routing\file_locator($this->filesystem, 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();
}
@@ -155,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'),
);
}
@@ -164,7 +171,8 @@ 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->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0'));
- $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
+ $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);
}
@@ -195,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'),
);
}
@@ -204,7 +215,8 @@ 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->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
+ $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);
}
@@ -235,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'),
);
}
@@ -244,7 +259,8 @@ 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->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
+ $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);
}
@@ -275,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'),
);
}
@@ -284,7 +303,8 @@ 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->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
+ $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);
}
@@ -315,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'),
);
}
@@ -324,7 +347,8 @@ 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->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
+ $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);
}
@@ -355,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'),
);
}
@@ -364,7 +391,8 @@ 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->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
+ $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);
}
@@ -404,7 +432,8 @@ 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->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
+ $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);
}
@@ -435,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'),
);
}
@@ -444,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->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
+ $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/controller_test.php b/tests/controller/controller_test.php
index 5781d3ebc1..431b26b2bc 100644
--- a/tests/controller/controller_test.php
+++ b/tests/controller/controller_test.php
@@ -38,11 +38,17 @@ class phpbb_controller_controller_test extends phpbb_test_case
));
}
- public function test_router_find_files()
+ public function test_router_default_loader()
{
- $router = new \phpbb\routing\router(new \phpbb\filesystem\filesystem(), dirname(__FILE__) . '/', 'php', PHPBB_ENVIRONMENT, $this->extension_manager);
- $router->find_routing_files($this->extension_manager->all_enabled(false));
- $routes = $router->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'));
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/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/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/fixtures/migrator_permission.xml b/tests/dbal/fixtures/migrator_permission.xml
index 08cec42a42..c07956fa85 100644
--- a/tests/dbal/fixtures/migrator_permission.xml
+++ b/tests/dbal/fixtures/migrator_permission.xml
@@ -27,5 +27,139 @@
<value>1</value>
<value>0</value>
</row>
+ <row>
+ <value>4</value>
+ <value>a_test</value>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>m_test</value>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>u_test</value>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ </row>
+ </table>
+
+ <table name="phpbb_groups">
+ <column>group_id</column>
+ <column>group_name</column>
+ <column>group_desc</column>
+ <row>
+ <value>2</value>
+ <value>REGISTERED</value>
+ <value></value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>GLOBAL_MODERATORS</value>
+ <value></value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>ADMINISTRATORS</value>
+ <value></value>
+ </row>
+ </table>
+
+ <table name="phpbb_acl_groups">
+ <column>group_id</column>
+ <column>auth_role_id</column>
+ <column>forum_id</column>
+ <row>
+ <value>2</value>
+ <value>5</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>5</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>10</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>1</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>5</value>
+ <value>0</value>
+ </row>
+ </table>
+
+ <table name="phpbb_acl_roles">
+ <column>role_id</column>
+ <column>role_name</column>
+ <column>role_type</column>
+ <column>role_description</column>
+ <row>
+ <value>1</value>
+ <value>ROLE_ADMIN_STANDARD</value>
+ <value>a_</value>
+ <value></value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>ROLE_USER_FULL</value>
+ <value>u_</value>
+ <value></value>
+ </row>
+ <row>
+ <value>10</value>
+ <value>ROLE_MOD_FULL</value>
+ <value>m_</value>
+ <value></value>
+ </row>
+ </table>
+
+ <table name="phpbb_acl_roles_data">
+ <column>role_id</column>
+ <column>auth_option_id</column>
+ <column>auth_setting</column>
+ <row>
+ <value>1</value>
+ <value>4</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>5</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>6</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>6</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>10</value>
+ <value>5</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>10</value>
+ <value>6</value>
+ <value>0</value>
+ </row>
</table>
</dataset>
diff --git a/tests/dbal/migrator_tool_module_test.php b/tests/dbal/migrator_tool_module_test.php
index 695a7e7a7f..a71334f23f 100644
--- a/tests/dbal/migrator_tool_module_test.php
+++ b/tests/dbal/migrator_tool_module_test.php
@@ -41,7 +41,10 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
$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 3d190e7a11..bfb2e07080 100644
--- a/tests/dbal/migrator_tool_permission_test.php
+++ b/tests/dbal/migrator_tool_permission_test.php
@@ -15,6 +15,12 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
class phpbb_dbal_migrator_tool_permission_test extends phpbb_database_test_case
{
+ public $group_ids = array(
+ 'REGISTERED' => 2,
+ 'GLOBAL_MODERATORS' => 4,
+ 'ADMINISTRATORS' => 5,
+ );
+
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/migrator_permission.xml');
@@ -158,4 +164,60 @@ class phpbb_dbal_migrator_tool_permission_test extends phpbb_database_test_case
}
$this->assertFalse($this->tool->exists('global_test', true));
}
+
+ public function test_permission_set_data()
+ {
+ return array(
+ array(
+ 'ADMINISTRATORS',
+ 'a_test',
+ 'group',
+ true,
+ ),
+ array(
+ 'GLOBAL_MODERATORS',
+ 'm_test',
+ 'group',
+ true,
+ ),
+ array(
+ 'REGISTERED',
+ 'u_test',
+ 'group',
+ true,
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider test_permission_set_data
+ */
+ public function test_permission_set($group_name, $auth_option, $type, $has_permission)
+ {
+ $this->tool->permission_set($group_name, $auth_option, $type, $has_permission);
+ $administrators_perm = $this->auth->acl_group_raw_data($this->group_ids['ADMINISTRATORS'], $auth_option);
+ $global_moderators_perm = $this->auth->acl_group_raw_data($this->group_ids['GLOBAL_MODERATORS'], $auth_option);
+ $registered_users_perm = $this->auth->acl_group_raw_data($this->group_ids['REGISTERED'], $auth_option);
+
+ switch($group_name)
+ {
+ case 'GLOBAL_MODERATORS':
+ $this->assertEquals(false, empty($administrators_perm), 'm_test is not empty for Administrators');
+ $this->assertEquals(false, empty($global_moderators_perm), 'm_test is not empty for Global moderators');
+ $this->assertEquals(true, empty($registered_users_perm), 'm_test empty for Registered users');
+ break;
+
+ case 'ADMINISTRATORS':
+ $this->assertEquals(false, empty($administrators_perm), 'a_test is not empty for Administrators');
+ $this->assertEquals(true, empty($global_moderators_perm), 'a_test is empty for Global moderators');
+ $this->assertEquals(true, empty($registered_users_perm), 'a_test is empty for Registered users');
+ break;
+
+ case 'REGISTERED':
+ $this->assertEquals(false, empty($administrators_perm), 'u_test is not empty for Administrators');
+ $this->assertEquals(false, empty($global_moderators_perm), 'u_test is not empty for Global moderators');
+ $this->assertEquals(false, empty($registered_users_perm), 'u_test is not empty for Registered users');
+ break;
+ }
+ }
}
diff --git a/tests/di/create_container_test.php b/tests/di/create_container_test.php
index d52fb6b085..2d94f1d778 100644
--- a/tests/di/create_container_test.php
+++ b/tests/di/create_container_test.php
@@ -31,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))
@@ -78,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);
@@ -94,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);
@@ -109,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);
@@ -119,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);
@@ -139,9 +130,9 @@ 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);
@@ -150,61 +141,21 @@ namespace
}
}
-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'),
- array('ext_name' => 'vendor/enabled-2'),
- array('ext_name' => 'vendor/enabled-3'),
- array('ext_name' => 'vendor/enabled_4'),
+ '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 f2e1145efa..1e9207d924 100644
--- a/tests/di/fixtures/config.php
+++ b/tests/di/fixtures/config.php
@@ -1,7 +1,7 @@
<?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';
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/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/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/event/exception_listener_test.php b/tests/event/exception_listener_test.php
index 608cde4f9b..e643fadf2c 100644
--- a/tests/event/exception_listener_test.php
+++ b/tests/event/exception_listener_test.php
@@ -83,10 +83,8 @@ class exception_listener extends phpbb_test_case
$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('common');
- $exception_listener = new \phpbb\event\kernel_exception_subscriber($template, $user);
+ $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/fixtures/adm/style/acp_bbcodes.html b/tests/event/fixtures/adm/style/acp_bbcodes.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/event/fixtures/adm/style/acp_bbcodes.html
diff --git a/tests/event/fixtures/normal_events.md.test b/tests/event/fixtures/normal_events.md.test
new file mode 100644
index 0000000000..47921c4e57
--- /dev/null
+++ b/tests/event/fixtures/normal_events.md.test
@@ -0,0 +1,20 @@
+acp_bbcodes_actions_append
+===
+* Location: adm/style/acp_bbcodes.html
+* Since: 3.1.0-a3
+* Changed: 3.1.0-a4
+* Purpose: desc1
+
+acp_bbcodes_actions_prepend
+===
+* Location: adm/style/acp_bbcodes.html
+* Since: 3.1.0-a5
+* Purpose: desc2
+
+acp_bbcodes_actions_prepend2
+===
+* Location: adm/style/acp_bbcodes.html
+* Since: 3.1.0-a4
+* Changed: 3.1.0-a5 Moved up
+* Changed: 3.1.0-a6 Moved down
+* Purpose: desc2
diff --git a/tests/event/md_exporter_test.php b/tests/event/md_exporter_test.php
index 28649e4f21..a6c1dc78de 100644
--- a/tests/event/md_exporter_test.php
+++ b/tests/event/md_exporter_test.php
@@ -11,21 +11,105 @@
*
*/
+require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
+
class phpbb_event_md_exporter_test extends phpbb_test_case
{
-
static public function crawl_eventsmd_data()
{
return array(
+ array('normal_events.md.test', null, null, array(
+ 'acp_bbcodes_actions_append' => array(
+ 'event' => 'acp_bbcodes_actions_append',
+ 'files' => array(
+ 'prosilver' => array(),
+ 'adm' => array('acp_bbcodes.html'),
+ ),
+ 'since' => '3.1.0-a3',
+ 'changed' => array(
+ '3.1.0-a4' => '',
+ ),
+ 'description' => 'desc1' . "\n",
+ ),
+ 'acp_bbcodes_actions_prepend' => array(
+ 'event' => 'acp_bbcodes_actions_prepend',
+ 'files' => array(
+ 'prosilver' => array(),
+ 'adm' => array('acp_bbcodes.html'),
+ ),
+ 'since' => '3.1.0-a5',
+ 'changed' => array(),
+ 'description' => 'desc2' . "\n",
+ ),
+ 'acp_bbcodes_actions_prepend2' => array(
+ 'event' => 'acp_bbcodes_actions_prepend2',
+ 'files' => array(
+ 'prosilver' => array(),
+ 'adm' => array('acp_bbcodes.html'),
+ ),
+ 'since' => '3.1.0-a4',
+ 'changed' => array(
+ '3.1.0-a5' => 'Moved up',
+ '3.1.0-a6' => 'Moved down',
+ ),
+ 'description' => 'desc2' . "\n",
+ ),
+ )),
+ array('normal_events.md.test', '3.1.0-a5', '3.1.0-a5', array(
+ 'acp_bbcodes_actions_prepend' => array(
+ 'event' => 'acp_bbcodes_actions_prepend',
+ 'files' => array(
+ 'prosilver' => array(),
+ 'adm' => array('acp_bbcodes.html'),
+ ),
+ 'since' => '3.1.0-a5',
+ 'changed' => array(),
+ 'description' => 'desc2' . "\n",
+ ),
+ 'acp_bbcodes_actions_prepend2' => array(
+ 'event' => 'acp_bbcodes_actions_prepend2',
+ 'files' => array(
+ 'prosilver' => array(),
+ 'adm' => array('acp_bbcodes.html'),
+ ),
+ 'since' => '3.1.0-a4',
+ 'changed' => array(
+ '3.1.0-a5' => 'Moved up',
+ '3.1.0-a6' => 'Moved down',
+ ),
+ 'description' => 'desc2' . "\n",
+ ),
+ )),
+ );
+ }
+
+ /**
+ * @dataProvider crawl_eventsmd_data
+ *
+ * @param string $file
+ * @param string $min_version
+ * @param string $max_version
+ * @param array $events
+ */
+ public function test_crawl_eventsmd($file, $min_version, $max_version, $events)
+ {
+ $exporter = new \phpbb\event\md_exporter(dirname(__FILE__) . '/fixtures/', null, $min_version, $max_version);
+ $this->assertSame(sizeof($events), $exporter->crawl_eventsmd($file, 'adm'));
+ $this->assertEquals($events, $exporter->get_events());
+ }
+
+ static public function crawl_phpbb_eventsmd_data()
+ {
+ return array(
array('styles'),
array('adm'),
);
}
/**
- * @dataProvider crawl_eventsmd_data
- */
- public function test_crawl_eventsmd($filter)
+ * @dataProvider crawl_phpbb_eventsmd_data
+ */
+ public function test_crawl_phpbb_eventsmd($filter)
{
global $phpbb_root_path;
$exporter = new \phpbb\event\md_exporter($phpbb_root_path);
diff --git a/tests/extension/modules_test.php b/tests/extension/modules_test.php
index cbcfdfb787..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,8 +64,7 @@ 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',
@@ -76,8 +83,7 @@ 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',
@@ -89,21 +95,7 @@ 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',
- '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',
@@ -115,18 +107,15 @@ 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',
@@ -138,18 +127,16 @@ 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',
@@ -175,7 +162,7 @@ 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',
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..a85844ee78
--- /dev/null
+++ b/tests/files/types_remote_test.php
@@ -0,0 +1,141 @@
+<?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 \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->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->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', 'DISALLOWED_CONTENT'),
+ array('1', 'http://google.com/.png', '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 = '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->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(array($expected), $file->error);
+ }
+
+ public function test_upload_timeout()
+ {
+ $type_remote = new \phpbb\files\types\remote($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);
+ $upload->upload_timeout = -5;
+
+ $file = $type_remote->upload('http://google.com/.png');
+
+ $this->assertSame(array('REMOTE_UPLOAD_TIMEOUT'), $file->error);
+ }
+
+ public function test_upload_wrong_path()
+ {
+ $type_remote = new \phpbb\files\types\foo($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/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
index 7ba0b0d991..9499888a1a 100644
--- a/tests/functional/controllers_compatibility_test.php
+++ b/tests/functional/controllers_compatibility_test.php
@@ -24,6 +24,19 @@ class phpbb_functional_controllers_compatibility_test extends phpbb_functional_t
$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);
diff --git a/tests/functional/extension_acp_test.php b/tests/functional/extension_acp_test.php
index 7be8957ec7..8a71a5ce04 100644
--- a/tests/functional/extension_acp_test.php
+++ b/tests/functional/extension_acp_test.php
@@ -41,6 +41,8 @@ class phpbb_functional_extension_acp_test extends phpbb_functional_test_case
{
parent::setUp();
+ $this->purge_cache();
+
$this->get_db();
// Clear the phpbb_ext table
diff --git a/tests/functional/extension_global_lang_test.php b/tests/functional/extension_global_lang_test.php
index 53bb9af5ca..f615114c08 100644
--- a/tests/functional/extension_global_lang_test.php
+++ b/tests/functional/extension_global_lang_test.php
@@ -52,6 +52,13 @@ class phpbb_functional_extension_global_lang_test extends phpbb_functional_test_
$this->purge_cache();
}
+ public function tearDown()
+ {
+ parent::tearDown();
+
+ $this->purge_cache();
+ }
+
public function test_load_extension_lang_globally()
{
$this->phpbb_extension_manager->enable('foo/bar');
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 9041c8dc69..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
*/
@@ -20,13 +22,19 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
static public $init_values = array();
+ public function setUp()
+ {
+ parent::setUp();
+ $this->purge_cache();
+ }
+
public function __construct($name = null, array $data = array(), $dataName = '')
{
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()
@@ -55,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()
@@ -132,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(
@@ -149,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}");
@@ -160,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',
@@ -171,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()
@@ -195,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()
@@ -266,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(
@@ -273,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(
@@ -325,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');
@@ -333,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'];
}
@@ -489,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'];
}
@@ -510,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()
@@ -609,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()
@@ -710,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(
@@ -752,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()
@@ -847,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);
@@ -863,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();
}
@@ -958,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(
@@ -998,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'];
}
@@ -1216,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'];
}
@@ -1316,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 = "?{$mode}={$feed_data['id']}";
+ $params = "/forum/{$feed_data['id']}";
+ $this->assert_feed($params, $feed_data);
+ }
+ else if ($mode === 't')
+ {
+ $params = "/topic/{$feed_data['id']}";
$this->assert_feed($params, $feed_data);
}
else
@@ -1342,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);
}
}
@@ -1354,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}");
}
}
@@ -1375,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}'");
}
}
@@ -1384,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}'");
}
}
@@ -1392,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 = "./download/file.php?id={$attachment['id']}";
+ $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}'");
}
}
}
@@ -1414,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}'");
}
}
}
@@ -1439,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'];
}
@@ -1455,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'];
}
@@ -1472,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 4aa1a83b30..7e0f192b40 100644
--- a/tests/functional/fileupload_remote_test.php
+++ b/tests/functional/fileupload_remote_test.php
@@ -11,15 +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();
@@ -27,8 +41,7 @@ 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))
{
@@ -38,9 +51,17 @@ class phpbb_functional_fileupload_remote_test extends phpbb_functional_test_case
$config['rand_seed'] = '';
$config['rand_seed_last_update'] = time() + 600;
- $user = new phpbb_mock_user();
- $user->lang = new phpbb_mock_lang();
$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;
+
+ $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($this->factory, $this->language, $this->php_ini, $this->request, $phpbb_root_path));
+ $this->phpbb_root_path = $phpbb_root_path;
}
public function tearDown()
@@ -52,30 +73,47 @@ class phpbb_functional_fileupload_remote_test extends phpbb_functional_test_case
public function test_invalid_extension()
{
- $upload = new fileupload($this->filesystem, '', 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($this->filesystem, '', 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($this->filesystem, '', 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($this->filesystem, '', 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/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/metadata_manager_test.php b/tests/functional/metadata_manager_test.php
index 080822d249..0d2fdf082e 100644
--- a/tests/functional/metadata_manager_test.php
+++ b/tests/functional/metadata_manager_test.php
@@ -24,6 +24,13 @@ class phpbb_functional_metadata_manager_test extends phpbb_functional_test_case
'foo/bar/',
);
+ public function tearDown()
+ {
+ $this->purge_cache();
+
+ parent::tearDown();
+ }
+
static public function setUpBeforeClass()
{
parent::setUpBeforeClass();
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/plupload_test.php b/tests/functional/plupload_test.php
index ee71597ffc..d358681ad1 100644
--- a/tests/functional/plupload_test.php
+++ b/tests/functional/plupload_test.php
@@ -33,6 +33,7 @@ class phpbb_functional_plupload_test extends phpbb_functional_test_case
public function setUp()
{
parent::setUp();
+ $this->purge_cache();
$this->set_extension_group_permission(1);
$this->path = __DIR__ . '/fixtures/files/';
$this->add_lang('posting');
diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php
index 5c083aef37..bf9e3eb51a 100644
--- a/tests/functional/posting_test.php
+++ b/tests/functional/posting_test.php
@@ -57,9 +57,9 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
$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\x88\xB3 \xF0\x9F\x9A\xB6");
+ $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\x88\xB3 \xF0\x9F\x9A\xB6", $crawler->text());
+ $this->assertContains("\xF0\x9F\x84\x90 \xF0\x9F\x84\x91", $crawler->text());
}
public function test_html_entities()
@@ -72,6 +72,20 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
$this->assertContains('&#128512;', $crawler->text());
}
+ public function test_quote()
+ {
+ $text = 'Test post </textarea>"\' &&amp;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
*/
@@ -79,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();
@@ -95,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()
+ );
}
}
@@ -152,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/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/fixtures/user_delete.xml b/tests/functions/fixtures/user_delete.xml
new file mode 100644
index 0000000000..4c4479d29b
--- /dev/null
+++ b/tests/functions/fixtures/user_delete.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_users">
+ <column>user_id</column>
+ <column>username_clean</column>
+ <column>username</column>
+ <column>user_permissions</column>
+ <column>user_sig</column>
+ <row>
+ <value>1</value>
+ <value>anonymous</value>
+ <value>anonymous</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>2</value>
+ <value>2</value>
+ <value></value>
+ <value></value>
+ </row>
+ </table>
+ <table name="phpbb_oauth_accounts">
+ <column>user_id</column>
+ <column>provider</column>
+ <column>oauth_provider_id</column>
+ <row>
+ <value>2</value>
+ <value>google</value>
+ <value>1234567890123456789</value>
+ </row>
+ </table>
+ <table name="phpbb_oauth_tokens">
+ <column>user_id</column>
+ <column>session_id</column>
+ <column>provider</column>
+ <column>oauth_token</column>
+ <row>
+ <value>2</value>
+ <value>897a897b797c8789997d7979879</value>
+ <value>auth.provider.oauth.service.google</value>
+ <value>{"accessToken":"ya29.YPHwCWVkrvwu1kgbYKiDNYaQ451ZuHy9OEQAGVME8if-WBzR-v7a9ftxbx41kaL)5VLEXB-6qJEvri","endOfLife":1429959670,"extraParams":{"token_type":"Bearer","id_token":"eyJhbGciOiJSUzI1NiIsImupZCI6IjE0YuRjNzc2MDQwYjUyNDZmNTI5OWFkZDVlMmQ1NWNOPTdjMDdlZTAifQ.eyJpc3MiOiJhY2NvdW90cy5nb78nbGUuY29tIiwic3ViIjoiMTExMDMwNwerNjM4MTM5NTQwMTM1IiwiYXpwIjoiOTk3MzUwMTY0NzE0LWhwOXJrYjZpcjM4MW80YjV1NjRpaGtmM29zMnRvbWxhLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJtYXJjLmFsZXhhbmRlci4zN0BnbWFpbC5jb20iLCJhdF9oYXNoIjoiWHk2b1JabnVZUWRfRTZDeDV0RkItdyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdWQiOiI5OTczNTAxNjQ3MTQtaHA5cmtiNmlyMzgxbzRiNXU2NGloa2Yzb3MydG9tbGEuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJpYXQiOjE0Mjk5NTYwNzEsImV4cCI6MTQyOTk1OTY3MX0.C5gfSzjqwlRRvVMuTP6jfWIuEHMXn55oYHsSA3eh97n2BZL0TZHhUm4K206Fgucd6ufAphan4l0J7y6tMAHLZPr-kk6KDINxWnPG-up99reblGutay0lRYjMCcrhJAOql8EI1bi84GyliZFYHL67pE0ZtSf-CMb1CeH18TFe-Fk"},"refreshToken":null,"token_class":"OAuth\\\\OAuth2\\\\Token\\\\StdOAuth2Token"}</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/functions/user_delete_test.php b/tests/functions/user_delete_test.php
new file mode 100644
index 0000000000..bd6b53c59f
--- /dev/null
+++ b/tests/functions/user_delete_test.php
@@ -0,0 +1,114 @@
+<?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_user.php';
+
+class phpbb_functions_user_delete_test extends phpbb_database_test_case
+{
+ /** @var \phpbb\db\driver\driver_interface */
+ protected $db;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/user_delete.xml');
+ }
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ global $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $user, $phpbb_root_path, $phpEx;
+
+ $this->db = $db = $this->new_dbal();
+ $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(
+ 'auth_method' => 'oauth',
+ 'auth_oauth_google_key' => 'foo',
+ 'auth_oauth_google_secret' => 'bar',
+ ));
+ $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);
+ $oauth_provider_google = new \phpbb\auth\provider\oauth\service\google($config, $request);
+ $oauth_provider_collection = new \phpbb\di\service_collection($phpbb_container);
+ $oauth_provider_collection->offsetSet('auth.provider.oauth.service.google', $oauth_provider_google);
+
+ $driver_helper = new \phpbb\passwords\driver\helper($config);
+ $passwords_drivers = array(
+ 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $driver_helper),
+ 'passwords.driver.bcrypt' => new \phpbb\passwords\driver\bcrypt($config, $driver_helper),
+ 'passwords.driver.salted_md5' => new \phpbb\passwords\driver\salted_md5($config, $driver_helper),
+ 'passwords.driver.phpass' => new \phpbb\passwords\driver\phpass($config, $driver_helper),
+ );
+
+ $passwords_helper = new \phpbb\passwords\helper;
+ // Set up passwords manager
+ $passwords_manager = new \phpbb\passwords\manager($config, $passwords_drivers, $passwords_helper, array_keys($passwords_drivers));
+
+ $oauth_provider = new \phpbb\auth\provider\oauth\oauth(
+ $db,
+ $config,
+ $passwords_manager,
+ $request,
+ $user,
+ 'phpbb_oauth_tokens',
+ 'phpbb_oauth_states',
+ 'phpbb_oauth_accounts',
+ $oauth_provider_collection,
+ 'phpbb_users',
+ $phpbb_container,
+ $this->phpbb_root_path,
+ $this->php_ext
+ );
+ $provider_collection->offsetSet('auth.provider.oauth', $oauth_provider);
+
+ $phpbb_container->set('auth.provider.oauth', $oauth_provider);
+ $phpbb_container->set('auth.provider.oauth.service.google', $oauth_provider_google);
+ $phpbb_container->set('auth.provider_collection', $provider_collection);
+ $phpbb_container->set('notification_manager', $notification_manager);
+ }
+
+ public function test_user_delete()
+ {
+ // Check that user is linked
+ $sql = 'SELECT ot.user_id AS user_id
+ FROM phpbb_oauth_accounts oa, phpbb_oauth_tokens ot
+ WHERE oa.user_id = 2
+ AND ot.user_id = oa.user_id';
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->assertEquals(array('user_id' => '2'), $row);
+
+ // user_delete() should return false
+ $this->assertFalse(user_delete('remove', array(2)));
+
+ // Make sure user link was removed
+ $sql = 'SELECT ot.user_id AS user_id
+ FROM phpbb_oauth_accounts oa, phpbb_oauth_tokens ot
+ WHERE oa.user_id = 2
+ AND ot.user_id = oa.user_id';
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->assertEmpty($row);
+ }
+}
diff --git a/tests/functions_acp/build_cfg_template_test.php b/tests/functions_acp/build_cfg_template_test.php
index 8ae78b97db..a8d7ae6f09 100644
--- a/tests/functions_acp/build_cfg_template_test.php
+++ b/tests/functions_acp/build_cfg_template_test.php
@@ -32,7 +32,7 @@ class phpbb_functions_acp_build_cfg_template_test extends phpbb_test_case
array('config_key_name' => '2'),
'config_key_name',
array(),
- '<input id="key_name" type="password" size="20" maxlength="128" name="config[config_key_name]" value="2" autocomplete="off" />',
+ '<input id="key_name" type="password" size="20" maxlength="128" name="config[config_key_name]" value="********" autocomplete="off" />',
),
array(
array('text', 0, 255),
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 0cb171c885..6d2e1fa20a 100644
--- a/tests/functions_user/delete_user_test.php
+++ b/tests/functions_user/delete_user_test.php
@@ -25,7 +25,7 @@ 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(
@@ -36,6 +36,18 @@ class phpbb_functions_user_delete_user_test extends phpbb_database_test_case
$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()
+ );
+ $provider_collection = new \phpbb\auth\provider_collection($phpbb_container, $config);
+ $provider_collection->add('auth.provider.db');
+ $phpbb_container->set(
+ 'auth.provider_collection',
+ $provider_collection
+ );
}
public function first_last_post_data()
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/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..c8e482e260
--- /dev/null
+++ b/tests/installer/installer_config_test.php
@@ -0,0 +1,79 @@
+<?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('foo');
+ $this->config->set_active_module('bar');
+ $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_name' => 'foo',
+ '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
index 95de403bd4..6a814e39dc 100644
--- a/tests/language/language_test.php
+++ b/tests/language/language_test.php
@@ -39,6 +39,20 @@ class phpbb_language_test extends phpbb_test_case
$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()
{
// No param
diff --git a/tests/lint_test.php b/tests/lint_test.php
index fb43196bae..70046bdfd2 100644
--- a/tests/lint_test.php
+++ b/tests/lint_test.php
@@ -84,6 +84,8 @@ class phpbb_lint_test extends phpbb_test_case
dirname(__FILE__) . '/../build/new_version',
dirname(__FILE__) . '/../build/old_versions',
dirname(__FILE__) . '/../phpBB/cache',
+ dirname(__FILE__) . '/../phpBB/ext',
+ dirname(__FILE__) . '/../phpBB/store',
// PHP Fatal error: Cannot declare class Container because the name is already in use in /var/www/projects/phpbb3/tests/../phpBB/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1-1.php on line 20
// https://gist.github.com/e003913ffd493da63cbc
dirname(__FILE__) . '/../phpBB/vendor',
diff --git a/tests/log/add_test.php b/tests/log/add_test.php
index cfc592a464..ea1ae74d53 100644
--- a/tests/log/add_test.php
+++ b/tests/log/add_test.php
@@ -92,5 +92,14 @@ class phpbb_log_add_test extends phpbb_database_test_case
// Invalid mode specified
$this->assertFalse($log->add('mode_does_not_exist', $user_id, $log_ip, $log_operation, $log_time));
+
+ // null user and null ip given
+ $this->assertEquals(3, $log->add($mode, null, null, $log_operation, $log_time), 'Adding log with null user_id and null user_ip failed');
+ $sql = 'SELECT user_id, log_ip FROM ' . LOG_TABLE . ' WHERE log_id = 3';
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+ $this->assertEquals(ANONYMOUS, $row['user_id'], 'Adding log with null user_id failed');
+ $this->assertEquals('', $row['log_ip'], 'Adding log with null user_ip failed');
}
}
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_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&amp;t=56'),
+ 'viewpost' => '',
'viewlogs' => append_sid("phpBB/mcp.$phpEx", 'i=logs&amp;mode=topic_logs&amp;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/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 1d9f5dc5bf..0116dced49 100644
--- a/tests/mock/controller_helper.php
+++ b/tests/mock/controller_helper.php
@@ -13,19 +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\routing\router $router, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem\filesystem_interface $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;
- $this->router = $router;
- }
-
public function get_current_url()
{
return '';
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/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/notification/base.php b/tests/notification/base.php
index 45b0b6f179..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,6 +66,7 @@ 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,
));
$lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
$lang = new \phpbb\language\language($lang_loader);
@@ -62,8 +74,9 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
$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\dummy(),
+ $cache_driver,
$this->config,
$this->db,
$phpbb_root_path,
@@ -72,41 +85,64 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
$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');
@@ -114,21 +150,14 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
protected function build_type($type)
{
- global $phpbb_root_path, $phpEx;
-
- $instance = 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');
-
- if ($type === 'phpbb\\notification\\type\\quote')
- {
- $instance->set_utils(new \phpbb\textformatter\s9e\utils);
- }
+ $instance = $this->container->get($type);
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/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 a24808fbbd..d16e198861 100644
--- a/tests/notification/group_request_test.php
+++ b/tests/notification/group_request_test.php
@@ -49,6 +49,11 @@ 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\dummy();
$this->get_test_case_helpers()->set_s9e_services();
diff --git a/tests/notification/manager_helper.php b/tests/notification/manager_helper.php
index 48bf5b177b..2e8699e1e0 100644
--- a/tests/notification/manager_helper.php
+++ b/tests/notification/manager_helper.php
@@ -37,40 +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);
-
- if ($item_type === 'phpbb\\notification\\type\\quote')
- {
- $item->set_utils(new \phpbb\textformatter\s9e\utils);
- }
-
- $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 04fb6658c3..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,10 +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,));
+ $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\dummy(),
+ $cache_driver,
$config,
$db,
$phpbb_root_path,
@@ -82,9 +91,12 @@ 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(
- new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ $lang,
'\phpbb\datetime'
));
$user->ip = '';
@@ -99,39 +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);
-
- if ($type === 'quote')
- {
- $class->set_utils(new \phpbb\textformatter\s9e\utils);
- }
-
- $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 8ad6a62b09..3fab8c05ba 100644
--- a/tests/notification/submit_post_type_quote_test.php
+++ b/tests/notification/submit_post_type_quote_test.php
@@ -51,7 +51,8 @@ class phpbb_notification_submit_post_type_quote_test extends phpbb_notification_
*/
public function submit_post_data()
{
- $parser = $this->get_test_case_helpers()->set_s9e_services()->get('text_formatter.parser');
+ // 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(
/**
diff --git a/tests/notification/user_list_trim_test.php b/tests/notification/user_list_trim_test.php
index f7b4fcb215..9f6eb492f6 100644
--- a/tests/notification/user_list_trim_test.php
+++ b/tests/notification/user_list_trim_test.php
@@ -55,13 +55,13 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
$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
);
}
diff --git a/tests/pagination/pagination_test.php b/tests/pagination/pagination_test.php
index 67c3d0a30f..6a3b46cdae 100644
--- a/tests/pagination/pagination_test.php
+++ b/tests/pagination/pagination_test.php
@@ -41,9 +41,12 @@ class phpbb_pagination_pagination_test extends phpbb_template_template_test_case
$manager = new phpbb_mock_extension_manager(dirname(__FILE__) . '/', array());
$this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1'));
- $router = new phpbb_mock_router($filesystem, dirname(__FILE__) . '/', 'php', PHPBB_ENVIRONMENT, $manager);
- $router->find_routing_files($manager->all_enabled(false));
- $router->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);
@@ -54,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, $router, $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/plupload/plupload_test.php b/tests/plupload/plupload_test.php
index aa7793567d..3312f4d0a0 100644
--- a/tests/plupload/plupload_test.php
+++ b/tests/plupload/plupload_test.php
@@ -48,7 +48,7 @@ class phpbb_plupload_test extends phpbb_test_case
$config,
new phpbb_mock_request,
new \phpbb\user($lang, '\phpbb\datetime'),
- new \phpbb\php\ini,
+ 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/search/mysql_test.php b/tests/search/mysql_test.php
index c0c16456f4..3a791f5e81 100644
--- a/tests/search/mysql_test.php
+++ b/tests/search/mysql_test.php
@@ -37,8 +37,9 @@ class phpbb_search_mysql_test extends phpbb_search_common_test_case
$config['fulltext_mysql_max_word_len'] = 254;
$this->db = $this->new_dbal();
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$error = null;
$class = self::get_search_wrapper('\phpbb\search\fulltext_mysql');
- $this->search = new $class($error, $phpbb_root_path, $phpEx, null, $config, $this->db, $user);
+ $this->search = new $class($error, $phpbb_root_path, $phpEx, null, $config, $this->db, $user, $phpbb_dispatcher);
}
}
diff --git a/tests/search/native_test.php b/tests/search/native_test.php
index 61fde7d098..29d0d0a8d3 100644
--- a/tests/search/native_test.php
+++ b/tests/search/native_test.php
@@ -33,11 +33,12 @@ class phpbb_search_native_test extends phpbb_search_test_case
$cache = new phpbb_mock_cache();
$this->db = $this->new_dbal();
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$error = null;
$class = self::get_search_wrapper('\phpbb\search\fulltext_native');
$config['fulltext_native_min_chars'] = 2;
$config['fulltext_native_max_chars'] = 14;
- $this->search = new $class($error, $phpbb_root_path, $phpEx, null, $config, $this->db, $user);
+ $this->search = new $class($error, $phpbb_root_path, $phpEx, null, $config, $this->db, $user, $phpbb_dispatcher);
}
public function keywords()
diff --git a/tests/search/postgres_test.php b/tests/search/postgres_test.php
index f96d71e2bc..97cca0e70c 100644
--- a/tests/search/postgres_test.php
+++ b/tests/search/postgres_test.php
@@ -37,8 +37,9 @@ class phpbb_search_postgres_test extends phpbb_search_common_test_case
$config['fulltext_postgres_max_word_len'] = 254;
$this->db = $this->new_dbal();
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$error = null;
$class = self::get_search_wrapper('\phpbb\search\fulltext_postgres');
- $this->search = new $class($error, $phpbb_root_path, $phpEx, null, $config, $this->db, $user);
+ $this->search = new $class($error, $phpbb_root_path, $phpEx, null, $config, $this->db, $user, $phpbb_dispatcher);
}
}
diff --git a/tests/template/template_includecss_test.php b/tests/template/template_includecss_test.php
index 062fc9493b..ac62e820ae 100644
--- a/tests/template/template_includecss_test.php
+++ b/tests/template/template_includecss_test.php
@@ -95,19 +95,19 @@ class phpbb_template_template_includecss_test extends phpbb_template_template_te
*/
array(
array('TEST' => 1),
- '<link href="tests/template/templates/child_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen, projection" />',
+ '<link href="tests/template/templates/child_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen" />',
),
array(
array('TEST' => 2),
- '<link href="tests/template/parent_templates/parent_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen, projection" />',
+ '<link href="tests/template/parent_templates/parent_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen" />',
),
array(
array('TEST' => 3),
- '<link href="tests/template/ext/include/css/styles/all/theme/test.css?assets_version=1" rel="stylesheet" type="text/css" media="screen, projection" />',
+ '<link href="tests/template/ext/include/css/styles/all/theme/test.css?assets_version=1" rel="stylesheet" type="text/css" media="screen" />',
),
array(
array('TEST' => 4),
- '<link href="tests/template/ext/include/css/styles/all/theme/child_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen, projection" />',
+ '<link href="tests/template/ext/include/css/styles/all/theme/child_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen" />',
),
);
}
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_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php
index 5136af5ad1..fa50d89a70 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
@@ -344,10 +343,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)
{
diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php
index 0fec3c2dff..b91894f9c0 100644
--- a/tests/test_framework/phpbb_functional_test_case.php
+++ b/tests/test_framework/phpbb_functional_test_case.php
@@ -12,7 +12,7 @@
*/
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
{
@@ -89,7 +89,6 @@ class phpbb_functional_test_case extends phpbb_test_case
// that were added in other tests are gone
$this->lang = array();
$this->add_lang('common');
- $this->purge_cache();
$db = $this->get_db();
@@ -285,120 +284,98 @@ 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'],
- ));
-
- // install/index.php?mode=install&sub=database
- $crawler = self::submit($form);
- self::assertContains('Successful connection', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form();
-
- // 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',
- ));
-
- // 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)
+ $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');
+
+ do
{
- self::markTestSkipped("Could not write $config_file file.");
+ $installer->run();
}
+ while (file_exists($phpbb_root_path . 'store/install_config.php'));
+
+ copy($config_file, $config_file_test);
- // 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)
@@ -863,15 +840,15 @@ class phpbb_functional_test_case extends phpbb_test_case
*/
static public function assert_response_html($status_code = 200)
{
- if ($status_code !== false)
- {
- self::assert_response_status_code($status_code);
- }
-
// Any output before the doc type means there was an error
$content = self::$client->getResponse()->getContent();
self::assertNotContains('[phpBB Debug]', $content);
self::assertStringStartsWith('<!DOCTYPE', trim($content), 'Output found before DOCTYPE specification.');
+
+ if ($status_code !== false)
+ {
+ self::assert_response_status_code($status_code);
+ }
}
/*
@@ -884,15 +861,15 @@ class phpbb_functional_test_case extends phpbb_test_case
*/
static public function assert_response_xml($status_code = 200)
{
- if ($status_code !== false)
- {
- self::assert_response_status_code($status_code);
- }
-
// Any output before the xml opening means there was an error
$content = self::$client->getResponse()->getContent();
self::assertNotContains('[phpBB Debug]', $content);
self::assertStringStartsWith('<?xml', trim($content), 'Output found before XML specification.');
+
+ if ($status_code !== false)
+ {
+ self::assert_response_status_code($status_code);
+ }
}
/**
diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php
index 210cda9a94..c4b653ec7c 100644
--- a/tests/test_framework/phpbb_test_case_helpers.php
+++ b/tests/test_framework/phpbb_test_case_helpers.php
@@ -315,7 +315,7 @@ class phpbb_test_case_helpers
public function set_s9e_services(ContainerInterface $container = null, $fixture = null, $styles_path = null)
{
static $first_run;
- global $phpbb_container, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
+ global $config, $phpbb_container, $phpbb_dispatcher, $phpbb_root_path, $phpEx, $request, $user;
$cache_dir = __DIR__ . '/../tmp/';
@@ -426,23 +426,28 @@ class phpbb_test_case_helpers
$cache_key_parser = $prefix . '_parser';
$cache_key_renderer = $prefix . '_renderer';
$container->set('cache.driver', $cache);
- $container->setParameter('cache.dir', $cache_dir);
+
+ if (!$container->isFrozen())
+ {
+ $container->setParameter('cache.dir', $cache_dir);
+ }
// Create a path_helper
- if (!$container->has('path_helper'))
- {
- $container->set(
- 'path_helper',
- new \phpbb\path_helper(
- new \phpbb\symfony_request(
- new phpbb_mock_request()
- ),
- new \phpbb\filesystem(),
- $this->test_case->getMock('\phpbb\request\request'),
- $phpbb_root_path,
- $phpEx
- )
- );
+ 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
@@ -463,8 +468,40 @@ class phpbb_test_case_helpers
$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, $cache_dir, $cache_key_parser, $cache_key_renderer);
+ $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
@@ -476,11 +513,21 @@ class phpbb_test_case_helpers
{
$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 = $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');
@@ -490,6 +537,14 @@ class phpbb_test_case_helpers
$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,
@@ -509,13 +564,10 @@ class phpbb_test_case_helpers
$dispatcher
);
- $config = ($container->has('config'))
- ? $container->get('config')
- : new \phpbb\config\config(array('smilies_path' => 'images/smilies', 'allow_nocensors' => false));
- $auth = ($container->has('auth')) ? $container->get('auth') : new \phpbb\auth\auth;
-
// Calls configured in services.yml
- $renderer->configure_smilies_path($config, $container->get('path_helper'));
+ $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);
@@ -528,4 +580,15 @@ class phpbb_test_case_helpers
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..e118801972 100644
--- a/tests/test_framework/phpbb_ui_test_case.php
+++ b/tests/test_framework/phpbb_ui_test_case.php
@@ -11,7 +11,7 @@
*
*/
-require_once __DIR__ . '/../../phpBB/includes/functions_install.php';
+require_once __DIR__ . '/mock/phpbb_mock_null_installer_task.php';
class phpbb_ui_test_case extends phpbb_test_case
{
@@ -118,87 +118,97 @@ 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());
-
- // install/index.php?mode=install&sub=requirements
- self::submit();
- self::assertContains('Installation compatibility', self::find_element('id', 'main')->getText());
-
- // install/index.php?mode=install&sub=database
- self::submit();
- self::assertContains('Database configuration', self::find_element('id', 'main')->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']);
-
- // Need to clear default phpbb_ prefix
- self::find_element('id','table_prefix')->clear();
- self::find_element('id','table_prefix')->sendKeys(self::$config['table_prefix']);
-
- // install/index.php?mode=install&sub=database
- self::submit();
- self::assertContains('Successful connection', self::find_element('id','main')->getText());
-
- // install/index.php?mode=install&sub=administrator
- self::submit();
- self::assertContains('Administrator configuration', self::find_element('id','main')->getText());
-
- 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');
-
- // install/index.php?mode=install&sub=administrator
- self::submit();
- self::assertContains('Tests passed', self::find_element('id','main')->getText());
-
- // install/index.php?mode=install&sub=config_file
- self::submit();
-
- // 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)
+ $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');
+
+ do
{
- self::markTestSkipped("Could not write $config_file file.");
+ $installer->run();
}
+ while (file_exists($phpbb_root_path . 'store/install_config.php'));
+
+ copy($config_file, $config_file_test);
- if (strpos(self::find_element('id','main')->getText(), 'The configuration file has been written') === false)
+ if (file_exists($phpbb_root_path . 'cache/install_lock'))
{
- self::submit('id', 'dldone');
+ unlink($phpbb_root_path . 'cache/install_lock');
}
- 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());
-
- 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']);
-
- // 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());
-
- // install/index.php?mode=install&sub=final
- self::submit();
- self::assertContains('You have successfully installed', self::find_element('id', 'main')->getText());
- 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);
}
}
diff --git a/tests/text_formatter/s9e/default_formatting_test.php b/tests/text_formatter/s9e/default_formatting_test.php
index 79232562cf..1f7df15434 100644
--- a/tests/text_formatter/s9e/default_formatting_test.php
+++ b/tests/text_formatter/s9e/default_formatting_test.php
@@ -15,10 +15,21 @@ 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)
+ 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);
@@ -26,6 +37,11 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case
$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));
@@ -68,7 +84,7 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case
),
array(
'[code]unparsed code[/code]',
- '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><code>unparsed code</code></div>'
+ '<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]',
@@ -116,7 +132,7 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case
),
array(
'[img]https://area51.phpbb.com/images/area51.png[/img]',
- '<img src="https://area51.phpbb.com/images/area51.png" alt="Image">'
+ '<img src="https://area51.phpbb.com/images/area51.png" class="postimage" alt="Image">'
),
array(
'[url]https://area51.phpbb.com/[/url]',
@@ -181,12 +197,12 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case
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><code>unparsed code [b]bold [i]bold + italic[/i][/b]</code></div>'
+ '<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><code>unparsed code [quote="username"]quoted[/quote]</code></div>'
+ '<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
@@ -195,7 +211,11 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case
),
array(
"[code]\tline1\n line2[/code]",
- '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><code>&nbsp; &nbsp;line1<br>' . "\n" . '&nbsp; line2</code></div>'
+ '<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 ...',
@@ -206,6 +226,36 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case
'... <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>'
),
@@ -214,9 +264,52 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case
'<blockquote><div><cite><a href="http://example.org" class="postlink">http://example.org</a> wrote:</cite>...</div></blockquote>'
),
array(
- '[quote="http://example.org"]...[/quote]',
+ '[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&amp;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
index 8382097544..8f8ec7ebc7 100644
--- a/tests/text_formatter/s9e/factory_test.php
+++ b/tests/text_formatter/s9e/factory_test.php
@@ -35,7 +35,7 @@ class phpbb_textformatter_s9e_factory_test extends phpbb_database_test_case
public function get_factory()
{
- global $phpbb_root_path;
+ global $config, $phpbb_root_path, $request, $user;
$this->cache = new phpbb_mock_cache;
$dal = new \phpbb\textformatter\data_access(
$this->new_dbal(),
@@ -49,11 +49,23 @@ class phpbb_textformatter_s9e_factory_test extends phpbb_database_test_case
$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;
}
@@ -127,14 +139,14 @@ class phpbb_textformatter_s9e_factory_test extends phpbb_database_test_case
public function test_local_url()
{
global $config, $user, $request;
- $config = array(
+ $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;
diff --git a/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html
index a17446581a..76a35542be 100644
--- a/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html
+++ b/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html
@@ -31,7 +31,7 @@
<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size -->
-<!-- BEGIN img --><img src="{URL}" alt="{L_IMAGE}" /><!-- END img -->
+<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img -->
<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url -->
diff --git a/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html
index cd2f0acae3..fad8d828fd 100644
--- a/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html
+++ b/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html
@@ -31,7 +31,7 @@
<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size -->
-<!-- BEGIN img --><img src="{URL}" alt="{L_IMAGE}" /><!-- END img -->
+<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img -->
<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url -->
diff --git a/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html
index 909c09df5a..3e38d13a32 100644
--- a/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html
+++ b/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html
@@ -31,7 +31,7 @@
<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size -->
-<!-- BEGIN img --><img src="{URL}" alt="{L_IMAGE}" /><!-- END img -->
+<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img -->
<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url -->
diff --git a/tests/text_formatter/s9e/renderer_test.php b/tests/text_formatter/s9e/renderer_test.php
index 3c0bbb96c7..ad5bfa78fc 100644
--- a/tests/text_formatter/s9e/renderer_test.php
+++ b/tests/text_formatter/s9e/renderer_test.php
@@ -112,7 +112,7 @@ class phpbb_textformatter_s9e_renderer_test extends phpbb_test_case
),
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" alt="Image">',
+ '<img src="http://example.org/foo.png" class="postimage" alt="Image">',
array('set_viewimg' => true)
),
array(
@@ -231,7 +231,7 @@ class phpbb_textformatter_s9e_renderer_test extends phpbb_test_case
),
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" alt="Image">'
+ '<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>',
diff --git a/tests/text_formatter/s9e/utils_test.php b/tests/text_formatter/s9e/utils_test.php
index b1b937709c..dade259790 100644
--- a/tests/text_formatter/s9e/utils_test.php
+++ b/tests/text_formatter/s9e/utils_test.php
@@ -98,17 +98,141 @@ class phpbb_textformatter_s9e_utils_test extends phpbb_test_case
array('foo')
),
array(
- '[quote="foo"]..[/quote] [quote="bar"]..[/quote]',
+ '[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]',
+ '[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)
diff --git a/tests/text_processing/decode_message_test.php b/tests/text_processing/decode_message_test.php
index c9c1da52d5..7de599f2b1 100644
--- a/tests/text_processing/decode_message_test.php
+++ b/tests/text_processing/decode_message_test.php
@@ -38,6 +38,14 @@ class phpbb_text_processing_decode_message_test extends phpbb_test_case
'<!-- 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
diff --git a/tests/text_processing/generate_text_for_display_test.php b/tests/text_processing/generate_text_for_display_test.php
index f2b0d6c78b..dba3713447 100644
--- a/tests/text_processing/generate_text_for_display_test.php
+++ b/tests/text_processing/generate_text_for_display_test.php
@@ -173,7 +173,7 @@ class phpbb_text_processing_generate_text_for_display_test extends phpbb_test_ca
),
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" alt="Image">'
+ '<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>',
diff --git a/tests/text_processing/message_parser_test.php b/tests/text_processing/message_parser_test.php
index 691c0d5b8a..bee1b3fca3 100644
--- a/tests/text_processing/message_parser_test.php
+++ b/tests/text_processing/message_parser_test.php
@@ -61,6 +61,13 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
->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.',
@@ -76,7 +83,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
if (isset($setup))
{
- $setup($parser, $phpbb_container, $this);
+ $setup($phpbb_container, $this);
}
$this->get_test_case_helpers()->set_s9e_services($phpbb_container);
@@ -286,7 +293,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_font_size', 200);
}
@@ -295,7 +302,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_font_size', 0);
}
@@ -304,7 +311,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[size=2000]2000[/size]',
'<t>[size=2000]2000[/size]</t>',
array(true, true, true, true, true, true, true),
- function ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_font_size', 200);
},
@@ -314,7 +321,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[size=0]0[/size]',
'<t>[size=0]0[/size]</t>',
array(true, true, true, true, true, true, true),
- function ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_font_size', 200);
}
@@ -323,7 +330,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_sig_font_size', 200);
}
@@ -332,7 +339,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[size=200]200[/size]',
'<t>[size=200]200[/size]</t>',
array(true, true, true, true, true, true, true, true, 'sig'),
- function ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_sig_font_size', 120);
},
@@ -342,7 +349,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_img_height', 12);
},
@@ -352,7 +359,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_img_width', 34);
},
@@ -362,7 +369,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_img_height', 0);
$phpbb_container->get('config')->set('max_post_img_width', 0);
@@ -372,7 +379,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_img_height', 100);
$phpbb_container->get('config')->set('max_post_img_width', 100);
@@ -382,7 +389,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_sig_img_height', 12);
$phpbb_container->get('config')->set('max_sig_img_width', 34);
@@ -392,7 +399,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_img_height', 12);
},
@@ -402,7 +409,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_img_height', 123);
},
@@ -412,7 +419,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'[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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_img_width', 456);
},
@@ -422,7 +429,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
':) :) :)',
'<r><E>:)</E> <E>:)</E> <E>:)</E></r>',
array(true, true, true, true, true, true, true, true),
- function ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_smilies', 3);
}
@@ -431,7 +438,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
':) :) :) :)',
'<r><E>:)</E> <E>:)</E> <E>:)</E> :)</r>',
array(true, true, true, true, true, true, true, true),
- function ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_smilies', 3);
},
@@ -441,7 +448,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
':) :) :) :)',
'<r><E>:)</E> <E>:)</E> <E>:)</E> <E>:)</E></r>',
array(true, true, true, true, true, true, true, true),
- function ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_smilies', 0);
}
@@ -450,7 +457,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
':) :) :) :)',
'<r><E>:)</E> <E>:)</E> <E>:)</E> <E>:)</E></r>',
array(true, true, true, true, true, true, true, true),
- function ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_sig_smilies', 3);
}
@@ -459,7 +466,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
':) :) :) :)',
'<r><E>:)</E> <E>:)</E> <E>:)</E> :)</r>',
array(true, true, true, true, true, true, true, true, 'sig'),
- function ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_sig_smilies', 3);
},
@@ -469,7 +476,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_urls', 2);
},
@@ -479,7 +486,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_post_urls', 0);
}
@@ -488,7 +495,7 @@ class phpbb_text_processing_message_parser_test extends phpbb_test_case
'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 ($parser, $phpbb_container)
+ function ($phpbb_container)
{
$phpbb_container->get('config')->set('max_sig_urls', 2);
}
diff --git a/tests/text_processing/tickets_data/PHPBB3-10587.html b/tests/text_processing/tickets_data/PHPBB3-10587.html
index dd0a483244..4c2e536989 100644
--- a/tests/text_processing/tickets_data/PHPBB3-10587.html
+++ b/tests/text_processing/tickets_data/PHPBB3-10587.html
@@ -1,2 +1,2 @@
-<a href="http://www.tx-gaming.net/warzone/tournament.php?tourney%5Bid%5D=34&amp;action=brackets" class="postlink">http://www.tx-gaming.net/warzone/tournament.php?tourney[id]=34&amp;action=brackets</a><br>
-<a href="http://www.tx-gaming.net/warzone/tournament.php?tourney%5Bid%5D=34&amp;action=brackets" class="postlink">link</a> \ No newline at end of file
+<a href="http://example.org/?tourney%5Bid%5D=34&amp;action=brackets" class="postlink">http://example.org/?tourney[id]=34&amp;action=brackets</a><br>
+<a href="http://example.org/?tourney%5Bid%5D=34&amp;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
index f81a35eb5f..84788b720d 100644
--- a/tests/text_processing/tickets_data/PHPBB3-10587.txt
+++ b/tests/text_processing/tickets_data/PHPBB3-10587.txt
@@ -1,2 +1,2 @@
-[url]http://www.tx-gaming.net/warzone/tournament.php?tourney[id]=34&action=brackets[/url]
-[url="http://www.tx-gaming.net/warzone/tournament.php?tourney[id]=34&action=brackets"]link[/url] \ No newline at end of file
+[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
index cdf8316df0..3ff117f171 100644
--- a/tests/text_processing/tickets_data/PHPBB3-10922.html
+++ b/tests/text_processing/tickets_data/PHPBB3-10922.html
@@ -1 +1,9 @@
-<a href="mailto:user@example.org">user@example.org</a><a href="mailto:user@example.org">...</a> \ No newline at end of file
+<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&amp;body=Sent%20from%20phpBB">user@example.org</a><br>
+<a href="mailto:user@example.org?subject=Hello&amp;body=Sent%20from%20phpBB">user@example.org</a><br>
+<a href="mailto:user@example.org?subject=Hello&amp;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
index 348f8a1541..e533ce6ed5 100644
--- a/tests/text_processing/tickets_data/PHPBB3-10922.txt
+++ b/tests/text_processing/tickets_data/PHPBB3-10922.txt
@@ -1 +1,9 @@
-[email]user@example.org[/email][email=user@example.org]...[/email] \ No newline at end of file
+[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
index f003ad3dfa..cd24df60e5 100644
--- a/tests/text_processing/tickets_data/PHPBB3-10989.html
+++ b/tests/text_processing/tickets_data/PHPBB3-10989.html
@@ -1,6 +1,6 @@
<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.
+ 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>
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
index d8e0f8d523..c286c0fee9 100644
--- a/tests/text_processing/tickets_data/PHPBB3-12195.html
+++ b/tests/text_processing/tickets_data/PHPBB3-12195.html
@@ -1 +1 @@
-<a href="//example.org/" class="postlink"><img src="//example.org/img.png" alt="Image"></a> \ No newline at end of file
+<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-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-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-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", '"', '&#39;', '&#40;', '&#41;'), 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-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&amp;terms=all&amp;author=&amp;fid%5B%5D=46&amp;sc=1&amp;sf=all&amp;sr=posts&amp;sk=t&amp;sd=d&amp;st=0&amp;ch=300&amp;t=0&amp;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_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&#46;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&#58;//example&#46;org/flash&#46;swf[/flash:abcd1234]]]></value>
+ <value>abcd1234</value>
+ <value>1</value>
+ <value><![CDATA[[flash=123,345:abcd1234]http&#58;//example&#46;org/flash&#46;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&#58;//example&#46;org/img&#46;png[/img:abcd1234]]]></value>
+ <value>abcd1234</value>
+ <value>1</value>
+ <value><![CDATA[[img:abcd1234]http&#58;//example&#46;org/img&#46;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&#58;//example&#46;org/flash&#46;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&#58;//example&#46;org/img&#46;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&#58;//example&#46;org/flash&#46;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&#58;//example&#46;org/img&#46;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&#58;//example&#46;org/flash&#46;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&#58;//example&#46;org/img&#46;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&#58;//example&#46;org/flash&#46;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&#58;//example&#46;org/img&#46;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&#58;//example&#46;org/flash&#46;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&#58;//example&#46;org/img&#46;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/upload/filespec_test.php b/tests/upload/filespec_test.php
index f953970f64..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
{
@@ -26,12 +25,16 @@ class phpbb_filespec_test extends phpbb_test_case
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, $phpbb_filesystem;
+ global $config, $phpbb_root_path, $phpEx;
if (!is_array($config))
{
@@ -45,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/';
@@ -76,8 +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 = $phpbb_filesystem = new \phpbb\filesystem\filesystem();
+ $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())
@@ -91,14 +100,13 @@ class phpbb_filespec_test extends phpbb_test_case
'error' => '',
);
- return new filespec(array_merge($upload_ary, $override), null, $this->filesystem, $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)
@@ -111,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
@@ -132,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
@@ -173,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'),
);
}
@@ -184,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)
@@ -200,7 +229,7 @@ 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)));
@@ -209,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(
@@ -226,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()
@@ -289,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 png jpg', true),
+ array('png_copy', 'png_moved', 'image/png', 'jpg', 'Image file type mismatch: expected extension png but extension jpg given.', true),
);
}
@@ -300,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;
@@ -311,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);
}
/**
@@ -336,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 9de384b64f..05cb8dcf93 100644
--- a/tests/upload/fileupload_test.php
+++ b/tests/upload/fileupload_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';
require_once __DIR__ . '/../mock/filespec.php';
class phpbb_fileupload_test extends phpbb_test_case
@@ -22,29 +21,80 @@ class phpbb_fileupload_test extends phpbb_test_case
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, $phpbb_filesystem;
+ 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->filesystem = $phpbb_filesystem = new \phpbb\filesystem\filesystem();
+ $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()
@@ -69,15 +119,38 @@ class phpbb_fileupload_test extends phpbb_test_case
public function test_common_checks_invalid_extension()
{
- $upload = new fileupload($this->filesystem, '', 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($this->filesystem, '', 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);
@@ -86,7 +159,9 @@ class phpbb_fileupload_test extends phpbb_test_case
public function test_common_checks_too_large()
{
- $upload = new fileupload($this->filesystem, '', 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);
@@ -95,7 +170,9 @@ class phpbb_fileupload_test extends phpbb_test_case
public function test_common_checks_valid_file()
{
- $upload = new fileupload($this->filesystem, '', 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));
@@ -103,33 +180,41 @@ class phpbb_fileupload_test extends phpbb_test_case
public function test_local_upload()
{
- $upload = new fileupload($this->filesystem, '', 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($this->filesystem, '', 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($this->filesystem, '', 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));
@@ -138,7 +223,10 @@ class phpbb_fileupload_test extends phpbb_test_case
public function test_valid_dimensions()
{
- $upload = new fileupload($this->filesystem, '', 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/imagesize_test.php b/tests/upload/imagesize_test.php
index bfea4b819d..d20e866dab 100644
--- a/tests/upload/imagesize_test.php
+++ b/tests/upload/imagesize_test.php
@@ -16,7 +16,7 @@ require_once(__DIR__ . '/../../phpBB/includes/functions.php');
class phpbb_upload_imagesize_test extends \phpbb_test_case
{
- /** @var \fastImageSize\fastImageSize */
+ /** @var \FastImageSize\FastImageSize */
protected $imagesize;
/** @var string Path to fixtures */
@@ -25,7 +25,7 @@ class phpbb_upload_imagesize_test extends \phpbb_test_case
public function setUp()
{
parent::setUp();
- $this->imagesize = new \fastImageSize\fastImageSize();
+ $this->imagesize = new \FastImageSize\FastImageSize();
$this->path = __DIR__ . '/fixture/';
}
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);