diff options
Diffstat (limited to 'tests/text_formatter')
25 files changed, 3134 insertions, 0 deletions
diff --git a/tests/text_formatter/s9e/bbcode_merger_test.php b/tests/text_formatter/s9e/bbcode_merger_test.php new file mode 100644 index 0000000000..5ec0c91971 --- /dev/null +++ b/tests/text_formatter/s9e/bbcode_merger_test.php @@ -0,0 +1,296 @@ +<?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_textformatter_s9e_bbcode_merger_test extends phpbb_test_case +{ + /** + * @dataProvider get_merge_bbcodes_tests + */ + public function test_merge_bbcodes($usage_without, $template_without, $usage_with, $template_with, $expected_usage, $expected_template) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $factory = $container->get('text_formatter.s9e.factory'); + $bbcode_merger = new \phpbb\textformatter\s9e\bbcode_merger($factory); + + $without = ['usage' => $usage_without, 'template' => $template_without]; + $with = ['usage' => $usage_with, 'template' => $template_with]; + $merged = $bbcode_merger->merge_bbcodes($without, $with); + + // Normalize the expected template's whitespace to match the default indentation + $expected_template = str_replace("\n\t\t\t\t", "\n", $expected_template); + $expected_template = str_replace("\t", ' ', $expected_template); + + $this->assertSame($expected_usage, $merged['usage']); + $this->assertSame($expected_template, $merged['template']); + } + + public function get_merge_bbcodes_tests() + { + return [ + [ + '[x]{TEXT}[/x]', + '<b>{TEXT}</b>', + + '[x={TEXT1}]{TEXT}[/x]', + '<b title="{TEXT1}">{TEXT}</b>', + + '[x={TEXT1?}]{TEXT}[/x]', + '<b> + <xsl:if test="@x"> + <xsl:attribute name="title"> + <xsl:value-of select="@x"/> + </xsl:attribute> + </xsl:if> + <xsl:apply-templates/> + </b>' + ], + [ + // The tokens' numbering differs between versions + '[x]{TEXT}[/x]', + '<b>{TEXT}</b>', + + '[x={TEXT1}]{TEXT2}[/x]', + '<b title="{TEXT1}">{TEXT2}</b>', + + '[x={TEXT1?}]{TEXT2}[/x]', + '<b> + <xsl:if test="@x"> + <xsl:attribute name="title"> + <xsl:value-of select="@x"/> + </xsl:attribute> + </xsl:if> + <xsl:apply-templates/> + </b>' + ], + [ + '[x]{URL}[/x]', + '<a href="{URL}">{URL}</a>', + + '[x={URL}]{TEXT}[/x]', + '<a href="{URL}">{TEXT}</a>', + + '[x={URL;useContent}]{TEXT}[/x]', + '<a href="{@x}"> + <xsl:apply-templates/> + </a>' + ], + [ + '[x]{URL}[/x]', + '<a href="{URL}">{L_GO_TO}: {URL}</a>', + + '[x={URL}]{TEXT}[/x]', + '<a href="{URL}">{L_GO_TO}: {TEXT}</a>', + + '[x={URL;useContent}]{TEXT}[/x]', + '<a href="{@x}">{L_GO_TO}: <xsl:apply-templates/></a>' + ], + [ + // Test that unsafe BBCodes can still be merged + '[script]{TEXT}[/script]', + '<script>{TEXT}</script>', + + '[script={TEXT1}]{TEXT2}[/script]', + '<script type="{TEXT1}">{TEXT2}</script>', + + '[script={TEXT1?}]{TEXT2}[/script]', + '<script> + <xsl:if test="@script"> + <xsl:attribute name="type"> + <xsl:value-of select="@script"/> + </xsl:attribute> + </xsl:if> + <xsl:apply-templates/> + </script>' + ], + [ + // https://www.phpbb.com/community/viewtopic.php?p=14848281#p14848281 + '[note]{TEXT}[/note]', + '<span class="prime_bbcode_note_spur" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);"></span><span class="prime_bbcode_note">{TEXT}</span>', + + '[note={TEXT1}]{TEXT2}[/note]', + '<span class="prime_bbcode_note_text" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);">{TEXT1}</span><span class="prime_bbcode_note_spur" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);"></span><span class="prime_bbcode_note">{TEXT2}</span>', + + '[note={TEXT1?}]{TEXT2}[/note]', + '<xsl:if test="@note"> + <span class="prime_bbcode_note_text" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);"> + <xsl:value-of select="@note"/> + </span> + </xsl:if> + <span class="prime_bbcode_note_spur" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);"/> + <span class="prime_bbcode_note"> + <xsl:apply-templates/> + </span>' + ], + [ + // https://www.phpbb.com/community/viewtopic.php?p=14768441#p14768441 + '[MI]{TEXT}[/MI]', + '<span style="color:red">MI:</span> <span style="color:#f6efe2">{TEXT}</span>', + + '[MI={TEXT2}]{TEXT1}[/MI]', + '<span style="color:red">MI for: "{TEXT2}":</span> <span style="color:#f6efe2">{TEXT1}</span>', + + '[MI={TEXT2?}]{TEXT1}[/MI]', + '<span style="color:red">MI<xsl:if test="@mi"> for: "<xsl:value-of select="@mi"/>"</xsl:if>:</span> + <xsl:text> </xsl:text> + <span style="color:#f6efe2"> + <xsl:apply-templates/> + </span>' + ], + [ + // https://www.phpbb.com/community/viewtopic.php?p=14700506#p14700506 + '[spoiler]{TEXT}[/spoiler]', + '<span class="spoiler"> {TEXT}</span>', + + '[spoiler={TEXT1}]{TEXT2}[/spoiler]', + '<div class="spoiler"><small> {TEXT1}</small>{TEXT2}</div>', + + '[spoiler={TEXT1?}]{TEXT2}[/spoiler]', + '<xsl:choose> + <xsl:when test="@spoiler"> + <div class="spoiler"> + <small> + <xsl:text> </xsl:text> + <xsl:value-of select="@spoiler"/> + </small> + <xsl:apply-templates/> + </div> + </xsl:when> + <xsl:otherwise> + <span class="spoiler"> + <xsl:text> </xsl:text> + <xsl:apply-templates/> + </span> + </xsl:otherwise> + </xsl:choose>' + ], + [ + // https://www.phpbb.com/community/viewtopic.php?p=14859676#p14859676 + '[AE]{TEXT}[/AE]', + '<table width="100%" border="1"> + <tr><td width="100%" align="center"> + <table width="100%" border="0"> + <tr> + <td width="100%" bgcolor="#E1E4F2"> + <table width="100%" border="0" bgcolor="#F5F5FF"> + <tr> + <td width="1%" bgcolor="#000000" nowrap align="left"> + <font color="#FFFFFF" face="Arial"><font size="1"><b> ACTIVE EFFECTS & CONDITIONS </b></font></font></td> + <td width="99%"> </td> + </tr> + <tr> + <td width="100%" bgcolor="#FFE5BA" colspan="2"> + <table width="100%" cellpadding="2"> + <tr> + <td width="100%" align="left" valign="top"> + {TEXT} + </td> + </tr> + </table> + </td> + </tr> + </table> + </td> + </tr> + </table> + </td></tr> + </table> + <p> </p>', + + '[AE={TEXT1}]{TEXT2}[/AE]', + '<table width="100%" border="1"> + <tr><td width="100%" align="center"> + <table width="100%" border="0"> + <tr> + <td width="100%" bgcolor="#E1E4F2"> + <table width="100%" border="0" bgcolor="#F5F5FF"> + <tr> + <td width="1%" bgcolor="#000000" nowrap align="left"> + <font color="#FFFFFF" face="Arial"><font size="1"><b> {TEXT1} </b></font></font></td> + <td width="99%"> </td> + </tr> + <tr> + <td width="100%" bgcolor="#FFE5BA" colspan="2"> + <table width="100%" cellpadding="2"> + <tr> + <td width="100%" align="left" valign="top"> + {TEXT2} + </td> + </tr> + </table> + </td> + </tr> + </table> + </td> + </tr> + </table> + </td></tr> + </table> + <p> </p>', + + '[AE={TEXT1?}]{TEXT2}[/AE]', + '<table width="100%" border="1"> + <tr> + <td width="100%" align="center"> + <table width="100%" border="0"> + <tr> + <td width="100%" bgcolor="#E1E4F2"> + <table width="100%" border="0" bgcolor="#F5F5FF"> + <tr> + <td width="1%" bgcolor="#000000" nowrap="nowrap" align="left"> + <font color="#FFFFFF" face="Arial"> + <font size="1"> + <b> <xsl:choose><xsl:when test="@ae"><xsl:text> </xsl:text><xsl:value-of select="@ae"/></xsl:when><xsl:otherwise>ACTIVE EFFECTS & CONDITIONS</xsl:otherwise></xsl:choose> </b> + </font> + </font> + </td> + <td width="99%"> </td> + </tr> + <tr> + <td width="100%" bgcolor="#FFE5BA" colspan="2"> + <table width="100%" cellpadding="2"> + <tr> + <td width="100%" align="left" valign="top"> + <xsl:apply-templates/> + </td> + </tr> + </table> + </td> + </tr> + </table> + </td> + </tr> + </table> + </td> + </tr> + </table> + <p> </p>' + ], + [ + // https://www.phpbb.com/community/viewtopic.php?f=438&t=2530451 + '[issue]{NUMBER}[/issue]', + '<a href="/default/issues/{NUMBER}"> Issue #{NUMBER}</a>', + + '[issue={SIMPLETEXT}]{NUMBER}[/issue]', + '<a href="/{SIMPLETEXT}/issues/{NUMBER}"> Issue #{NUMBER} ({SIMPLETEXT})</a>', + + '[issue={SIMPLETEXT?}]{NUMBER}[/issue]', + '<a> + <xsl:choose> + <xsl:when test="@issue"><xsl:attribute name="href">/<xsl:value-of select="@issue"/>/issues/<xsl:value-of select="@content"/></xsl:attribute> Issue #<xsl:value-of select="@content"/> (<xsl:value-of select="@issue"/>)</xsl:when> + <xsl:otherwise><xsl:attribute name="href">/default/issues/<xsl:value-of select="@content"/></xsl:attribute> Issue #<xsl:value-of select="@content"/></xsl:otherwise> + </xsl:choose> + </a>' + ], + ]; + } +} diff --git a/tests/text_formatter/s9e/default_formatting_test.php b/tests/text_formatter/s9e/default_formatting_test.php new file mode 100644 index 0000000000..1aa4f0bc3a --- /dev/null +++ b/tests/text_formatter/s9e/default_formatting_test.php @@ -0,0 +1,317 @@ +<?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_textformatter_s9e_default_formatting_test extends phpbb_test_case +{ + public function test_bbcode_code_lang_is_saved() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $parser = $container->get('text_formatter.parser'); + + $original = '[code]...[/code][code=php]...[/code]'; + $expected = '<r><CODE><s>[code]</s>...<e>[/code]</e></CODE><CODE lang="php"><s>[code=php]</s>...<e>[/code]</e></CODE></r>'; + + $this->assertXmlStringEqualsXmlString($expected, $parser->parse($original)); + } + + /** + * @dataProvider get_default_formatting_tests + */ + public function test_default_formatting($original, $expected, $setup = null) + { + $fixture = __DIR__ . '/fixtures/default_formatting.xml'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture); + + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + if (isset($setup)) + { + call_user_func($setup, $container); + } + + $parsed_text = $parser->parse($original); + + $this->assertSame($expected, $renderer->render($parsed_text)); + } + + public function get_default_formatting_tests() + { + return array( + array( + '[b]bold[/b]', + '<span style="font-weight:bold">bold</span>' + ), + array( + '[u]underlined[/u]', + '<span style="text-decoration:underline">underlined</span>' + ), + array( + '[i]italic[/i]', + '<span style="font-style:italic">italic</span>' + ), + array( + '[color=#FF0000]colored[/color]', + '<span style="color:#FF0000">colored</span>' + ), + array( + '[color=red]colored[/color]', + '<span style="color:red">colored</span>' + ), + array( + '[size=75]smaller[/size]', + '<span style="font-size: 75%; line-height: normal">smaller</span>' + ), + array( + '[quote]quoted[/quote]', + '<blockquote class="uncited"><div>quoted</div></blockquote>' + ), + array( + '[quote="username"]quoted[/quote]', + '<blockquote><div><cite>username wrote:</cite>quoted</div></blockquote>' + ), + array( + '[code]unparsed code[/code]', + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code</code></pre></div>' + ), + array( + '[list]no item[/list]', + '<ul><li>no item</li></ul>' + ), + array( + '[*]unparsed', + '[*]unparsed' + ), + array( + '[list][*]item[/list]', + '<ul><li>item</li></ul>' + ), + array( + '[list][*]item[/*][/list]', + '<ul><li>item</li></ul>' + ), + array( + '[list=1][*]item[/list]', + '<ol style="list-style-type:decimal"><li>item</li></ol>' + ), + array( + '[list=a][*]item[/list]', + '<ol style="list-style-type:lower-alpha"><li>item</li></ol>' + ), + array( + '[list=i][*]item[/list]', + '<ol style="list-style-type:lower-roman"><li>item</li></ol>' + ), + array( + '[list=I][*]item[/list]', + '<ol style="list-style-type:upper-roman"><li>item</li></ol>' + ), + array( + '[list=disc][*]item[/list]', + '<ul style="list-style-type:disc"><li>item</li></ul>' + ), + array( + '[list=circle][*]item[/list]', + '<ul style="list-style-type:circle"><li>item</li></ul>' + ), + array( + '[list=square][*]item[/list]', + '<ul style="list-style-type:square"><li>item</li></ul>' + ), + array( + '[img]https://area51.phpbb.com/images/area51.png[/img]', + '<img src="https://area51.phpbb.com/images/area51.png" class="postimage" alt="Image">' + ), + array( + '[url]https://area51.phpbb.com/[/url]', + '<a href="https://area51.phpbb.com/" class="postlink">https://area51.phpbb.com/</a>' + ), + array( + '[url=https://area51.phpbb.com/]Area51[/url]', + '<a href="https://area51.phpbb.com/" class="postlink">Area51</a>' + ), + array( + '[email]bbcode-test@phpbb.com[/email]', + '<a href="mailto:bbcode-test@phpbb.com">bbcode-test@phpbb.com</a>' + ), + array( + '[email=bbcode-test@phpbb.com]Email[/email]', + '<a href="mailto:bbcode-test@phpbb.com">Email</a>' + ), + array( + '[attachment=0]filename[/attachment]', + '<div class="inline-attachment"><!-- ia0 -->filename<!-- ia0 --></div>' + ), + array( + // PHPBB3-1401 - correct: parsed + '[quote="[test]test"]test [ test[/quote]', + '<blockquote><div><cite>[test]test wrote:</cite>test [ test</div></blockquote>' + ), + array( + // PHPBB3-6117 - correct: parsed + '[quote]test[/quote] test ] and [ test [quote]test[/quote]', + '<blockquote class="uncited"><div>test</div></blockquote> test ] and [ test <blockquote class="uncited"><div>test</div></blockquote>' + ), + array( + // PHPBB3-6200 - correct: parsed + '[quote="["]test[/quote]', + '<blockquote><div><cite>[ wrote:</cite>test</div></blockquote>' + ), + array( + // PHPBB3-9364 - quoted: "test[/[/b]quote] test" / non-quoted: "[/quote] test" - also failed if layout distorted + '[quote]test[/[/b]quote] test [/quote][/quote] test', + '<blockquote class="uncited"><div>test[/[/b]quote] test </div></blockquote>[/quote] test' + ), + array( + // PHPBB3-8096 - first quote tag parsed, second quote tag unparsed + '[quote="a"]a[/quote][quote="a]a[/quote]', + '<blockquote><div><cite>a wrote:</cite>a</div></blockquote>[quote="a]a[/quote]' + ), + array( + // Allow textual bbcodes in textual bbcodes + '[b]bold [i]bold + italic[/i][/b]', + '<span style="font-weight:bold">bold <span style="font-style:italic">bold + italic</span></span>' + ), + array( + // Allow textual bbcodes in url with description + '[url=https://area51.phpbb.com/]Area51 [i]italic[/i][/url]', + '<a href="https://area51.phpbb.com/" class="postlink">Area51 <span style="font-style:italic">italic</span></a>' + ), + array( + // Allow url with description in textual bbcodes + '[i]italic [url=https://area51.phpbb.com/]Area51[/url][/i]', + '<span style="font-style:italic">italic <a href="https://area51.phpbb.com/" class="postlink">Area51</a></span>' + ), + array( + // Do not parse textual bbcodes in code + '[code]unparsed code [b]bold [i]bold + italic[/i][/b][/code]', + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code [b]bold [i]bold + italic[/i][/b]</code></pre></div>' + ), + array( + // Do not parse quote bbcodes in code + '[code]unparsed code [quote="username"]quoted[/quote][/code]', + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code [quote="username"]quoted[/quote]</code></pre></div>' + ), + array( + // Textual bbcode nesting into textual bbcode + '[b]bold [i]bold + italic[/b] italic[/i]', + '<span style="font-weight:bold">bold <span style="font-style:italic">bold + italic</span></span><span style="font-style:italic"> italic</span>' + ), + array( + "[code]\tline1\n line2[/code]", + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>' . "\tline1\n line2</code></pre></div>" + ), + array( + "[code]\n\tline1\n line2[/code]", + '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>' . "\tline1\n line2</code></pre></div>" + ), + array( + '... http://example.org ...', + '... <a href="http://example.org" class="postlink">http://example.org</a> ...' + ), + array( + '... www.example.org ...', + '... <a href="http://www.example.org" class="postlink">www.example.org</a> ...' + ), + array( + // From make_clickable_test.php + 'www.phpbb.com/community/?', + '<a href="http://www.phpbb.com/community/" class="postlink">www.phpbb.com/community/</a>?' + ), + array( + // From make_clickable_test.php + 'http://www.phpbb.com/community/path/to/long/url/file.ext#section', + '<a href="http://www.phpbb.com/community/path/to/long/url/file.ext#section" class="postlink">http://www.phpbb.com/community/path/to/ ... xt#section</a>' + ), + array( + 'http://localhost/ http://localhost/phpbb/ http://localhost/phpbb/viewforum.php?f=1', + '<a href="http://localhost/" class="postlink">http://localhost/</a> <a href="http://localhost/phpbb/" class="postlink">http://localhost/phpbb/</a> <a href="http://localhost/phpbb/viewforum.php?f=1" class="postlink">viewforum.php?f=1</a>' + ), + array( + 'http://localhost/phpbb/viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + '<a href="http://localhost/phpbb/viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" class="postlink">viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxx ... xxxxxxxxxx</a>' + ), + array( + '[url]http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0[/url]', + '<a href="http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0" class="postlink">http://example.org/0xxxxxxxxxxxxxxxxxxx ... xxxxxxxxx0</a>' + ), + array( + '[URL]http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0[/url]', + '<a href="http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0" class="postlink">http://example.org/0xxxxxxxxxxxxxxxxxxx ... xxxxxxxxx0</a>' + ), + array( + '[url=http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[/url]', + '<a href="http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" class="postlink">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</a>' + ), + array( + '[url=http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[/url]', + '<a href="http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" class="postlink">http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</a>' + ), + array( + '[quote="[url=http://example.org]xxx[/url]"]...[/quote]', + '<blockquote><div><cite><a href="http://example.org" class="postlink">xxx</a> wrote:</cite>...</div></blockquote>' + ), + array( + '[quote="[url]http://example.org[/url]"]...[/quote]', + '<blockquote><div><cite><a href="http://example.org" class="postlink">http://example.org</a> wrote:</cite>...</div></blockquote>' + ), + array( + '[quote=http://example.org]...[/quote]', + '<blockquote><div><cite><a href="http://example.org" class="postlink">http://example.org</a> wrote:</cite>...</div></blockquote>' + ), + array( + "[quote]\nThis is a long quote that is definitely going to exceed 80 characters\n[/quote]\n\nFollowed by a reply", + "<blockquote class=\"uncited\"><div>\nThis is a long quote that is definitely going to exceed 80 characters\n</div></blockquote>\n\nFollowed by a reply" + ), + array( + '[quote=Username post_id=123]...[/quote]', + '<blockquote><div><cite>Username wrote: <a href="phpBB/viewtopic.php?p=123#p123" data-post-id="123" onclick="if(document.getElementById(hash.substr(1)))href=hash">↑</a></cite>...</div></blockquote>' + ), + array( + // Users are not allowed to submit their own URL for the post + '[quote="Username" post_url="http://fake.example.org"]...[/quote]', + '<blockquote><div><cite>Username wrote:</cite>...</div></blockquote>' + ), + array( + '[quote=Username time=58705871]...[/quote]', + '<blockquote><div><cite>Username wrote:<div class="responsive-hide">1971-11-11 11:11:11</div></cite>...</div></blockquote>' + ), + array( + '[quote=Username user_id=123]...[/quote]', + '<blockquote><div><cite><a href="phpBB/memberlist.php?mode=viewprofile&u=123">Username</a> wrote:</cite>...</div></blockquote>' + ), + array( + // Users are not allowed to submit their own URL for the profile + '[quote=Username profile_url=http://fake.example.org]...[/quote]', + '<blockquote><div><cite>Username wrote:</cite>...</div></blockquote>' + ), + array( + // From phpbb_textformatter_s9e_utils_test::test_generate_quote() + '[quote=\'[quote="foo"]\']...[/quote]', + '<blockquote><div><cite>[quote="foo"] wrote:</cite>...</div></blockquote>' + ), + array( + "Emoji: \xF0\x9F\x98\x80", + 'Emoji: <img alt="' . "\xF0\x9F\x98\x80" . '" class="emoji smilies" draggable="false" src="//twemoji.maxcdn.com/2/svg/1f600.svg">' + ), + array( + "Emoji: \xF0\x9F\x98\x80", + "Emoji: \xF0\x9F\x98\x80", + function ($container) + { + $container->get('text_formatter.renderer')->set_viewsmilies(false); + } + ), + ); + } +} diff --git a/tests/text_formatter/s9e/factory_test.php b/tests/text_formatter/s9e/factory_test.php new file mode 100644 index 0000000000..0d780a19a9 --- /dev/null +++ b/tests/text_formatter/s9e/factory_test.php @@ -0,0 +1,314 @@ +<?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__ . '/../../test_framework/phpbb_database_test_case.php'; + +class phpbb_textformatter_s9e_factory_test extends phpbb_database_test_case +{ + public function setUp() + { + $this->cache = new phpbb_mock_cache; + $this->dispatcher = new phpbb_mock_event_dispatcher; + parent::setUp(); + } + + public function getDataSet() + { + return $this->createXMLDataSet(__DIR__ . '/fixtures/factory.xml'); + } + + public function get_cache_dir() + { + return __DIR__ . '/../../tmp/'; + } + + public function get_factory($styles_path = null) + { + global $config, $phpbb_root_path, $request, $symfony_request, $user; + + if (!isset($styles_path)) + { + $styles_path = $phpbb_root_path . 'styles/'; + } + + $this->cache = new phpbb_mock_cache; + $dal = new \phpbb\textformatter\data_access( + $this->new_dbal(), + 'phpbb_bbcodes', + 'phpbb_smilies', + 'phpbb_styles', + 'phpbb_words', + $styles_path + ); + $factory = new \phpbb\textformatter\s9e\factory( + $dal, + $this->cache, + $this->dispatcher, + new \phpbb\config\config(array('allowed_schemes_links' => 'http,https,ftp')), + new \phpbb\textformatter\s9e\link_helper, + $this->getMockBuilder('phpbb\\log\\log_interface')->getMock(), + $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; + $symfony_request = new \phpbb\symfony_request($request); + $user = new phpbb_mock_user; + + return $factory; + } + + public function run_configurator_assertions($configurator) + { + $this->assertInstanceOf('s9e\\TextFormatter\\Configurator', $configurator); + + $this->assertTrue(isset($configurator->plugins['Autoemail'])); + $this->assertTrue(isset($configurator->plugins['Autolink'])); + + $this->assertTrue(isset($configurator->BBCodes['B'])); + $this->assertTrue(isset($configurator->BBCodes['CODE'])); + $this->assertTrue(isset($configurator->BBCodes['COLOR'])); + $this->assertTrue(isset($configurator->BBCodes['EMAIL'])); + $this->assertTrue(isset($configurator->BBCodes['FLASH'])); + $this->assertTrue(isset($configurator->BBCodes['I'])); + $this->assertTrue(isset($configurator->BBCodes['IMG'])); + $this->assertTrue(isset($configurator->BBCodes['LIST'])); + $this->assertTrue(isset($configurator->BBCodes['*'])); + $this->assertTrue(isset($configurator->BBCodes['QUOTE'])); + $this->assertTrue(isset($configurator->BBCodes['SIZE'])); + $this->assertTrue(isset($configurator->BBCodes['U'])); + $this->assertTrue(isset($configurator->BBCodes['URL'])); + + // This custom BBCode should be set + $this->assertTrue(isset($configurator->BBCodes['CUSTOM'])); + + $this->assertTrue(isset($configurator->Emoticons[':D'])); + } + + public function test_get_configurator() + { + $configurator = $this->get_factory()->get_configurator(); + $this->run_configurator_assertions($configurator); + + // Test with twigified bbcode.html + $configurator = $this->get_factory(__DIR__ . '/fixtures/styles/')->get_configurator(); + $this->run_configurator_assertions($configurator); + + } + + public function test_regenerate() + { + extract($this->get_factory()->regenerate()); + + $this->assertInstanceOf('s9e\\TextFormatter\\Parser', $parser); + $this->assertInstanceOf('s9e\\TextFormatter\\Renderer', $renderer); + + $renderer_data = $this->cache->get('_foo_renderer'); + $this->assertEquals($parser, $this->cache->get('_foo_parser'), 'The parser was not cached'); + $this->assertEquals(get_class($renderer), $renderer_data['class']); + $this->assertInstanceOf('s9e\\TextFormatter\\Plugins\\Censor\\Helper', $renderer_data['censor']); + + $file = $this->get_cache_dir() . get_class($renderer) . '.php'; + $this->assertFileExists($file); + unlink($file); + } + + public function test_tidy() + { + $factory = $this->get_factory(); + + // Create a fake "old" cache file + $old_file = $this->get_cache_dir() . 's9e_foo.php'; + touch($old_file); + + // Create a current renderer + extract($factory->regenerate()); + $new_file = $this->get_cache_dir() . get_class($renderer) . '.php'; + + // Tidy the cache + $factory->tidy(); + + $this->assertFileExists($new_file, 'The current renderer has been deleted'); + $this->assertFileNotExists($old_file, 'The old renderer has not been deleted'); + + unlink($new_file); + } + + public function test_local_url() + { + global $config, $user, $request, $symfony_request; + $config = new \phpbb\config\config(array( + 'force_server_vars' => true, + 'server_protocol' => 'http://', + 'server_name' => 'path', + 'server_port' => 80, + 'script_path' => '/to', + 'cookie_secure' => false + )); + $user = new phpbb_mock_user; + $request = new phpbb_mock_request; + $symfony_request = new \phpbb\symfony_request($request); + + $fixture = __DIR__ . '/fixtures/local_url.xml'; + $renderer = $this->get_test_case_helpers()->set_s9e_services(null, $fixture)->get('text_formatter.renderer'); + + $this->assertSame( + '<a href="http://path/to/foo">http://path/to/foo</a>', + $renderer->render('<r><LOCAL content="foo"><s>[local]</s>foo<e>[/local]</e></LOCAL></r>') + ); + } + + public function test_smilies_special_chars() + { + // Use a smiley that contains every special chars in every field + $fixture = __DIR__ . '/fixtures/smilies_special_chars.xml'; + $renderer = $this->get_test_case_helpers()->set_s9e_services(null, $fixture)->get('text_formatter.renderer'); + + $this->assertSame( + '<img class="smilies" src="phpBB/images/smilies/%22%27%3C&%3E.png" width="15" height="17" alt=""\'<&>" title=""\'<&>">', + $renderer->render('<r><E>"\'<&></E></r>') + ); + } + + public function test_duplicate_smilies() + { + $fixture = __DIR__ . '/fixtures/smilies_duplicate.xml'; + $parser = $this->get_test_case_helpers()->set_s9e_services(null, $fixture)->get('text_formatter.parser'); + + $this->assertSame( + '<r><E>:)</E></r>', + $parser->parse(':)') + ); + } + + /** + * @testdox {INTTEXT} is supported in custom BBCodes + */ + public function test_inttext_token() + { + $fixture = __DIR__ . '/fixtures/inttext_token.xml'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture); + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + $original = '[spoiler=ɎɆS]text[/spoiler]'; + $expected = '<div class="spoiler"><div class="title">ɎɆS</div><div class="content">text</div></div>'; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + + $original = '[spoiler=N:O:P:E]text[/spoiler]'; + $expected = $original; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + } + + /** + * @testdox Preserves comments in custom BBCodes + */ + public function test_preserve_comments() + { + $fixture = __DIR__ . '/fixtures/preserve_comments.xml'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture); + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + $original = '[X]'; + $expected = '<!-- comment -->'; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + } + + /** + * @testdox Accepts unsafe custom BBCodes + */ + public function test_unsafe_bbcode() + { + $fixture = __DIR__ . '/fixtures/unsafe_bbcode.xml'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture); + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + $original = '[xss=javascript:alert(1)]text[/xss]'; + $expected = '<a href="javascript:alert(1)">text</a>'; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + } + + /** + * @testdox Accepts unsafe default BBCodes + */ + public function test_unsafe_default_bbcodes() + { + $fixture = __DIR__ . '/fixtures/unsafe_default_bbcodes.xml'; + $style_dir = __DIR__ . '/fixtures/styles/'; + $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture, $style_dir); + $parser = $container->get('text_formatter.parser'); + $renderer = $container->get('text_formatter.renderer'); + + $original = '[b]alert(1)[/b]'; + $expected = '<script>alert(1)</script>'; + $this->assertSame($expected, $renderer->render($parser->parse($original))); + } + + /** + * @testdox Logs malformed BBCodes + */ + public function test_malformed_bbcodes() + { + $log = $this->getMockBuilder('phpbb\\log\\log_interface')->getMock(); + $log->expects($this->once()) + ->method('add') + ->with('critical', null, null, 'LOG_BBCODE_CONFIGURATION_ERROR', false, ['[x !x]{TEXT}[/x]', 'Cannot interpret the BBCode definition']); + + $container = new phpbb_mock_container_builder; + $container->set('log', $log); + + $fixture = __DIR__ . '/fixtures/malformed_bbcode.xml'; + $this->get_test_case_helpers()->set_s9e_services($container, $fixture); + } + + /** + * @testdox get_configurator() triggers events before and after configuration + */ + public function test_configure_events() + { + $this->dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $this->dispatcher + ->expects($this->at(0)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_configure_before', + $this->callback(array($this, 'configure_event_callback')) + ) + ->will($this->returnArgument(1)); + $this->dispatcher + ->expects($this->at(1)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_configure_after', + $this->callback(array($this, 'configure_event_callback')) + ) + ->will($this->returnArgument(1)); + + $this->get_factory()->get_configurator(); + } + + public function configure_event_callback($vars) + { + return isset($vars['configurator']) && $vars['configurator'] instanceof \s9e\TextFormatter\Configurator; + } +} diff --git a/tests/text_formatter/s9e/fixtures/default_formatting.xml b/tests/text_formatter/s9e/fixtures/default_formatting.xml new file mode 100644 index 0000000000..2b7236fb30 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/default_formatting.xml @@ -0,0 +1,466 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>1</value> + <value>:D</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>1</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>:-D</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>1</value> + </row> + <row> + <value>3</value> + <value>:grin:</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>3</value> + <value>1</value> + </row> + <row> + <value>4</value> + <value>:)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>4</value> + <value>1</value> + </row> + <row> + <value>5</value> + <value>:-)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>5</value> + <value>1</value> + </row> + <row> + <value>6</value> + <value>:smile:</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>6</value> + <value>1</value> + </row> + <row> + <value>7</value> + <value>;)</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>7</value> + <value>1</value> + </row> + <row> + <value>8</value> + <value>;-)</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>8</value> + <value>1</value> + </row> + <row> + <value>9</value> + <value>:wink:</value> + <value>Wink</value> + <value>icon_e_wink.gif</value> + <value>15</value> + <value>17</value> + <value>9</value> + <value>1</value> + </row> + <row> + <value>10</value> + <value>:(</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>10</value> + <value>1</value> + </row> + <row> + <value>11</value> + <value>:-(</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>11</value> + <value>1</value> + </row> + <row> + <value>12</value> + <value>:sad:</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>12</value> + <value>1</value> + </row> + <row> + <value>13</value> + <value>:o</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>13</value> + <value>1</value> + </row> + <row> + <value>14</value> + <value>:-o</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>14</value> + <value>1</value> + </row> + <row> + <value>15</value> + <value>:eek:</value> + <value>Surprised</value> + <value>icon_e_surprised.gif</value> + <value>15</value> + <value>17</value> + <value>15</value> + <value>1</value> + </row> + <row> + <value>16</value> + <value>:shock:</value> + <value>Shocked</value> + <value>icon_eek.gif</value> + <value>15</value> + <value>17</value> + <value>16</value> + <value>1</value> + </row> + <row> + <value>17</value> + <value>:?</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>17</value> + <value>1</value> + </row> + <row> + <value>18</value> + <value>:-?</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>18</value> + <value>1</value> + </row> + <row> + <value>19</value> + <value>:???:</value> + <value>Confused</value> + <value>icon_e_confused.gif</value> + <value>15</value> + <value>17</value> + <value>19</value> + <value>1</value> + </row> + <row> + <value>20</value> + <value>8-)</value> + <value>Cool</value> + <value>icon_cool.gif</value> + <value>15</value> + <value>17</value> + <value>20</value> + <value>1</value> + </row> + <row> + <value>21</value> + <value>:cool:</value> + <value>Cool</value> + <value>icon_cool.gif</value> + <value>15</value> + <value>17</value> + <value>21</value> + <value>1</value> + </row> + <row> + <value>22</value> + <value>:lol:</value> + <value>Laughing</value> + <value>icon_lol.gif</value> + <value>15</value> + <value>17</value> + <value>22</value> + <value>1</value> + </row> + <row> + <value>23</value> + <value>:x</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>23</value> + <value>1</value> + </row> + <row> + <value>24</value> + <value>:-x</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>24</value> + <value>1</value> + </row> + <row> + <value>25</value> + <value>:mad:</value> + <value>Mad</value> + <value>icon_mad.gif</value> + <value>15</value> + <value>17</value> + <value>25</value> + <value>1</value> + </row> + <row> + <value>26</value> + <value>:P</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>26</value> + <value>1</value> + </row> + <row> + <value>27</value> + <value>:-P</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>27</value> + <value>1</value> + </row> + <row> + <value>28</value> + <value>:razz:</value> + <value>Razz</value> + <value>icon_razz.gif</value> + <value>15</value> + <value>17</value> + <value>28</value> + <value>1</value> + </row> + <row> + <value>29</value> + <value>:oops:</value> + <value>Embarrassed</value> + <value>icon_redface.gif</value> + <value>15</value> + <value>17</value> + <value>29</value> + <value>1</value> + </row> + <row> + <value>30</value> + <value>:cry:</value> + <value>Crying or Very Sad</value> + <value>icon_cry.gif</value> + <value>15</value> + <value>17</value> + <value>30</value> + <value>1</value> + </row> + <row> + <value>31</value> + <value>:evil:</value> + <value>Evil or Very Mad</value> + <value>icon_evil.gif</value> + <value>15</value> + <value>17</value> + <value>31</value> + <value>1</value> + </row> + <row> + <value>32</value> + <value>:twisted:</value> + <value>Twisted Evil</value> + <value>icon_twisted.gif</value> + <value>15</value> + <value>17</value> + <value>32</value> + <value>1</value> + </row> + <row> + <value>33</value> + <value>:roll:</value> + <value>Rolling Eyes</value> + <value>icon_rolleyes.gif</value> + <value>15</value> + <value>17</value> + <value>33</value> + <value>1</value> + </row> + <row> + <value>34</value> + <value>:!:</value> + <value>Exclamation</value> + <value>icon_exclaim.gif</value> + <value>15</value> + <value>17</value> + <value>34</value> + <value>1</value> + </row> + <row> + <value>35</value> + <value>:?:</value> + <value>Question</value> + <value>icon_question.gif</value> + <value>15</value> + <value>17</value> + <value>35</value> + <value>1</value> + </row> + <row> + <value>36</value> + <value>:idea:</value> + <value>Idea</value> + <value>icon_idea.gif</value> + <value>15</value> + <value>17</value> + <value>36</value> + <value>1</value> + </row> + <row> + <value>37</value> + <value>:arrow:</value> + <value>Arrow</value> + <value>icon_arrow.gif</value> + <value>15</value> + <value>17</value> + <value>37</value> + <value>1</value> + </row> + <row> + <value>38</value> + <value>:|</value> + <value>Neutral</value> + <value>icon_neutral.gif</value> + <value>15</value> + <value>17</value> + <value>38</value> + <value>1</value> + </row> + <row> + <value>39</value> + <value>:-|</value> + <value>Neutral</value> + <value>icon_neutral.gif</value> + <value>15</value> + <value>17</value> + <value>39</value> + <value>1</value> + </row> + <row> + <value>40</value> + <value>:mrgreen:</value> + <value>Mr. Green</value> + <value>icon_mrgreen.gif</value> + <value>15</value> + <value>17</value> + <value>40</value> + <value>1</value> + </row> + <row> + <value>41</value> + <value>:geek:</value> + <value>Geek</value> + <value>icon_e_geek.gif</value> + <value>17</value> + <value>17</value> + <value>41</value> + <value>1</value> + </row> + <row> + <value>42</value> + <value>:ugeek:</value> + <value>Uber Geek</value> + <value>icon_e_ugeek.gif</value> + <value>17</value> + <value>18</value> + <value>42</value> + <value>1</value> + </row> + </table> + + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + <row> + <value>1</value> + <value>prosilver</value> + <value>&copy; phpBB Group</value> + <value>1</value> + <value>prosilver</value> + <value>kNg=</value> + <value>0</value> + <value></value> + </row> + </table> + + <table name="phpbb_words"> + <column>word_id</column> + <column>word</column> + <column>replacement</column> + + <row> + <value>1</value> + <value>apple</value> + <value>banana</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/default_lang.xml b/tests/text_formatter/s9e/fixtures/default_lang.xml new file mode 100644 index 0000000000..2cfde4aab2 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/default_lang.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + + <row> + <value>13</value> + <value>foo</value> + <value></value> + <value>1</value> + <value>[foo]{TEXT}[/foo]</value> + <value>{L_FOO_BAR}</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/factory.xml b/tests/text_formatter/s9e/fixtures/factory.xml new file mode 100644 index 0000000000..9ae52e9747 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/factory.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>custom</value> + <value></value> + <value>1</value> + <value>[custom]{TEXT}[/custom]</value> + <value><span style="color:red">{TEXT}</span></value> + <value>!\[custom\](.*?)\[/custom\]!ies</value> + <value>'[custom:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/custom:$uid]'</value> + <value>!\[custom:$uid\](.*?)\[/custom:$uid\]!s</value> + <value><span style="color:red">${1}</span></value> + </row> + <row> + <value>14</value> + <value>unsafe</value> + <value></value> + <value>1</value> + <value>[unsafe]{TEXT}[/unsafe]</value> + <value><script>{TEXT}</script></value> + <value>!\[unsafe\](.*?)\[/unsafe\]!ies</value> + <value>'[unsafe:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/unsafe:$uid]'</value> + <value>!\[unsafe:$uid\](.*?)\[/unsafe:$uid\]!s</value> + <value><script>${1}</script></value> + </row> + </table> + + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>1</value> + <value>:D</value> + <value>Very Happy</value> + <value>icon_e_biggrin.gif</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>1</value> + </row> + <row> + <value>4</value> + <value>:)</value> + <value>Smile</value> + <value>icon_e_smile.gif</value> + <value>15</value> + <value>17</value> + <value>4</value> + <value>1</value> + </row> + <row> + <value>10</value> + <value>:(</value> + <value>Sad</value> + <value>icon_e_sad.gif</value> + <value>15</value> + <value>17</value> + <value>10</value> + <value>1</value> + </row> + </table> + + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + + <row> + <value>1</value> + <value>prosilver</value> + <value>&copy; phpBB Group</value> + <value>1</value> + <value>prosilver</value> + <value>kNg=</value> + <value>0</value> + <value></value> + </row> + </table> + + <table name="phpbb_words"> + <column>word_id</column> + <column>word</column> + <column>replacement</column> + + <row> + <value>1</value> + <value>apple</value> + <value>banana</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/inttext_token.xml b/tests/text_formatter/s9e/fixtures/inttext_token.xml new file mode 100644 index 0000000000..30b971f315 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/inttext_token.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>spoiler=</value> + <value></value> + <value>1</value> + <value>[spoiler={INTTEXT}]{TEXT}[/spoiler]</value> + <value><![CDATA[<div class="spoiler"><div class="title">{INTTEXT}</div><div class="content">{TEXT}</div></div>]]></value> + <value><![CDATA[!\[spoiler\=([\p{L}\p{N}\-+,_. ]+)\](.*?)\[/spoiler\]!iues]]></value> + <value><![CDATA['[spoiler=${1}:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${2}')).'[/spoiler:$uid]']]></value> + <value><![CDATA[!\[spoiler\=([\p{L}\p{N}\-+,_. ]+):$uid\](.*?)\[/spoiler:$uid\]!su]]></value><value><![CDATA[<div class="spoiler"><div class="title">${1}</div><div class="content">${2}</div></div>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/local_url.xml b/tests/text_formatter/s9e/fixtures/local_url.xml new file mode 100644 index 0000000000..9db2bf4710 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/local_url.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>local</value> + <value></value> + <value>1</value> + <value>[local]{LOCAL_URL}[/local]</value> + <value><![CDATA[<a href="{LOCAL_URL}">{LOCAL_URL}</a>]]></value> + <value><*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:#(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?)\[/local\]!ie]]></value> + <value><![CDATA['[local:$uid]'.$this->bbcode_specialchars('${1}').'[/local:$uid]']]></value> + <value><((?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:#(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?)(?-i)\[/local:$uid\]!s]]></value> + <value><![CDATA[<a href="http://path/to/phpBB/${1}">http://path/to/phpBB/${1}</a>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/malformed_bbcode.xml b/tests/text_formatter/s9e/fixtures/malformed_bbcode.xml new file mode 100644 index 0000000000..7e7aa1a39c --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/malformed_bbcode.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>x</value> + <value></value> + <value>1</value> + <value>[x !x]{TEXT}[/x]</value> + <value>...</value> + <value/> + <value/> + <value/> + <value/> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/preserve_comments.xml b/tests/text_formatter/s9e/fixtures/preserve_comments.xml new file mode 100644 index 0000000000..f81d366aad --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/preserve_comments.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>X</value> + <value></value> + <value>1</value> + <value>[X][/X]</value> + <value><![CDATA[<!-- comment -->]]></value> + <value><![CDATA[!\[x\]\[/x\]!i]]></value> + <value><![CDATA[[x:$uid][/x:$uid]]]></value> + <value><![CDATA[[x:$uid][/x:$uid]]]></value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/smilies_duplicate.xml b/tests/text_formatter/s9e/fixtures/smilies_duplicate.xml new file mode 100644 index 0000000000..9645f3e516 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/smilies_duplicate.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>1</value> + <value>:)</value> + <value>:)</value> + <value>foo.png</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>:)</value> + <value>:)</value> + <value>bar.png</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>2</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml b/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml new file mode 100644 index 0000000000..d3a7cfa4f7 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_smilies"> + <column>smiley_id</column> + <column>code</column> + <column>emotion</column> + <column>smiley_url</column> + <column>smiley_width</column> + <column>smiley_height</column> + <column>smiley_order</column> + <column>display_on_posting</column> + <row> + <value>1</value> + <value>"'<&></value> + <value>"'<&></value> + <value>"'<&>.png</value> + <value>15</value> + <value>17</value> + <value>2</value> + <value>1</value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/style_inheritance.xml b/tests/text_formatter/s9e/fixtures/style_inheritance.xml new file mode 100644 index 0000000000..a692d0ef2d --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/style_inheritance.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + + <row> + <value>1</value> + <value>foo</value> + <value></value> + <value>1</value> + <value>foo</value> + <!-- Bitfield for "b" only --> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + <row> + <value>2</value> + <value>fooplus</value> + <value></value> + <value>1</value> + <value>fooplus</value> + <value>QA==</value> + <value>1</value> + <value></value> + </row> + <row> + <value>3</value> + <value>fooplusplus</value> + <value></value> + <value>1</value> + <value>fooplusplus</value> + <value>QA==</value> + <value>2</value> + <value></value> + </row> + <row> + <value>4</value> + <value>bar</value> + <value></value> + <value>1</value> + <value>bar</value> + <!-- Bitfield for "b" only --> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + <row> + <value>5</value> + <value>barplus</value> + <value></value> + <value>1</value> + <value>barplus</value> + <value>QA==</value> + <value>4</value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/styles.xml b/tests/text_formatter/s9e/fixtures/styles.xml new file mode 100644 index 0000000000..8004412aea --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + + <row> + <value>1</value> + <value>foo</value> + <value></value> + <value>1</value> + <value>foo</value> + <!-- Bitfield for "b" only --> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + <row> + <value>2</value> + <value>bar</value> + <value></value> + <value>1</value> + <value>bar</value> + <!-- Bitfield for "b" only --> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html new file mode 100644 index 0000000000..76a35542be --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html @@ -0,0 +1,40 @@ +<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open --> +<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default --> +<!-- BEGIN ulist_close --></ul><!-- END ulist_close --> + +<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open --> +<!-- BEGIN olist_close --></ol><!-- END olist_close --> + +<!-- BEGIN listitem --><li><!-- END listitem --> +<!-- BEGIN listitem_close --></li><!-- END listitem_close --> + +<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open --> +<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open --> +<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close --> + +<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open --> +<!-- BEGIN code_close --></code></div><!-- END code_close --> + +<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open --> +<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close --> + +<!-- BEGIN b_open --><b><!-- END b_open --> +<!-- BEGIN b_close --></b><!-- END b_close --> + +<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open --> +<!-- BEGIN u_close --></span><!-- END u_close --> + +<!-- BEGIN i_open --><em><!-- END i_open --> +<!-- BEGIN i_close --></em><!-- END i_close --> + +<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color --> + +<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size --> + +<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img --> + +<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url --> + +<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email --> + +<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash --> diff --git a/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html new file mode 100644 index 0000000000..fad8d828fd --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html @@ -0,0 +1,40 @@ +<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open --> +<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default --> +<!-- BEGIN ulist_close --></ul><!-- END ulist_close --> + +<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open --> +<!-- BEGIN olist_close --></ol><!-- END olist_close --> + +<!-- BEGIN listitem --><li><!-- END listitem --> +<!-- BEGIN listitem_close --></li><!-- END listitem_close --> + +<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open --> +<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open --> +<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close --> + +<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open --> +<!-- BEGIN code_close --></code></div><!-- END code_close --> + +<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open --> +<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close --> + +<!-- BEGIN b_open --><b class="barplus"><!-- END b_open --> +<!-- BEGIN b_close --></b><!-- END b_close --> + +<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open --> +<!-- BEGIN u_close --></span><!-- END u_close --> + +<!-- BEGIN i_open --><em><!-- END i_open --> +<!-- BEGIN i_close --></em><!-- END i_close --> + +<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color --> + +<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size --> + +<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img --> + +<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url --> + +<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email --> + +<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash --> diff --git a/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html new file mode 100644 index 0000000000..3e38d13a32 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html @@ -0,0 +1,40 @@ +<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open --> +<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default --> +<!-- BEGIN ulist_close --></ul><!-- END ulist_close --> + +<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open --> +<!-- BEGIN olist_close --></ol><!-- END olist_close --> + +<!-- BEGIN listitem --><li><!-- END listitem --> +<!-- BEGIN listitem_close --></li><!-- END listitem_close --> + +<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open --> +<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open --> +<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close --> + +<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open --> +<!-- BEGIN code_close --></code></div><!-- END code_close --> + +<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open --> +<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close --> + +<!-- BEGIN b_open --><strong><!-- END b_open --> +<!-- BEGIN b_close --></strong><!-- END b_close --> + +<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open --> +<!-- BEGIN u_close --></span><!-- END u_close --> + +<!-- BEGIN i_open --><em><!-- END i_open --> +<!-- BEGIN i_close --></em><!-- END i_close --> + +<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color --> + +<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size --> + +<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img --> + +<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url --> + +<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email --> + +<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash --> diff --git a/tests/text_formatter/s9e/fixtures/styles/prosilver/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/prosilver/template/bbcode.html new file mode 100644 index 0000000000..22be395499 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles/prosilver/template/bbcode.html @@ -0,0 +1,75 @@ +{% for ulist_open in loops.ulist_open %}<ul style="list-style-type: {{ LIST_TYPE }}">{% endfor %} +{% for ulist_open_default in loops.ulist_open_default %}<ul>{% endfor %} +{% for ulist_close in loops.ulist_close %}</ul>{% endfor %} + +{% for olist_open in loops.olist_open %}<ol style="list-style-type: {{ LIST_TYPE }}">{% endfor %} +{% for olist_close in loops.olist_close %}</ol>{% endfor %} + +{% for listitem in loops.listitem %}<li>{% endfor %} +{% for listitem_close in loops.listitem_close %}</li>{% endfor %} + +{% for quote_username_open in loops.quote_username_open %}<blockquote><div><cite>{{ USERNAME }} {{ lang('WROTE') }}{{ lang('COLON') }}</cite>{% endfor %} +{% for quote_open in loops.quote_open %}<blockquote class="uncited"><div>{% endfor %} +{% for quote_close in loops.quote_close %}</div></blockquote>{% endfor %} +{% for quote_extended in loops.quote_extended %} +<blockquote> + <xsl:if test="not(@author)"> + <xsl:attribute name="class">uncited</xsl:attribute> + </xsl:if> + <div> + <xsl:if test="@author"> + <cite> + <xsl:choose> + <xsl:when test="@url"> + <a href="{@url}" class="postlink"><xsl:value-of select="@author"/></a> + </xsl:when> + <xsl:when test="@profile_url"> + <a href="{@profile_url}"><xsl:value-of select="@author"/></a> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@author"/> + </xsl:otherwise> + </xsl:choose> + <xsl:text> </xsl:text> + <xsl:value-of select="$L_WROTE"/> + <xsl:value-of select="$L_COLON"/> + <xsl:if test="@post_url"> + <xsl:text> </xsl:text> + <a href="{@post_url}" data-post-id="{@post_id}" onclick="if(document.getElementById(hash.substr(1)))href=hash">↑</a> + </xsl:if> + <xsl:if test="@date"> + <div class="responsive-hide"><xsl:value-of select="@date"/></div> + </xsl:if> + </cite> + </xsl:if> + <xsl:apply-templates/> + </div> +</blockquote> +{% endfor %} + +{% for code_open in loops.code_open %}<div class="codebox"><p>{{ lang('CODE') }}{{ lang('COLON') }} <a href="#" onclick="selectCode(this); return false;">{{ lang('SELECT_ALL_CODE') }}</a></p><pre><code>{% endfor %} +{% for code_close in loops.code_close %}</code></pre></div>{% endfor %} + +{% for inline_attachment_open in loops.inline_attachment_open %}<div class="inline-attachment">{% endfor %} +{% for inline_attachment_close in loops.inline_attachment_close %}</div>{% endfor %} + +{% for b_open in loops.b_open %}<strong class="text-strong">{% endfor %} +{% for b_close in loops.b_close %}</strong>{% endfor %} + +{% for u_open in loops.u_open %}<span style="text-decoration: underline">{% endfor %} +{% for u_close in loops.u_close %}</span>{% endfor %} + +{% for i_open in loops.i_open %}<em class="text-italics">{% endfor %} +{% for i_close in loops.i_close %}</em>{% endfor %} + +{% for color in loops.color %}<span style="color: {{ COLOR }}">{{ TEXT }}</span>{% endfor %} + +{% for size in loops.size %}<span style="font-size: {{ SIZE }}%; line-height: 116%;">{{ TEXT }}</span>{% endfor %} + +{% for img in loops.img %}<img src="{{ URL }}" class="postimage" alt="{{ lang('IMAGE') }}" />{% endfor %} + +{% for url in loops.url %}<a href="{{ URL }}" class="postlink">{{ DESCRIPTION }}</a>{% endfor %} + +{% for email in loops.email %}<a href="mailto:{{ EMAIL }}">{{ DESCRIPTION }}</a>{% endfor %} + +{% for flash in loops.flash %}<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{{ WIDTH }}" height="{{ HEIGHT }}"><param name="movie" value="{{ URL }}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{{ URL }}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{{ WIDTH }}" height="{{ HEIGHT }}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object>{% endfor %} diff --git a/tests/text_formatter/s9e/fixtures/styles/unsafe/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/unsafe/template/bbcode.html new file mode 100644 index 0000000000..f3932f9b78 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/styles/unsafe/template/bbcode.html @@ -0,0 +1,40 @@ +<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open --> +<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default --> +<!-- BEGIN ulist_close --></ul><!-- END ulist_close --> + +<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open --> +<!-- BEGIN olist_close --></ol><!-- END olist_close --> + +<!-- BEGIN listitem --><li><!-- END listitem --> +<!-- BEGIN listitem_close --></li><!-- END listitem_close --> + +<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open --> +<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open --> +<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close --> + +<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open --> +<!-- BEGIN code_close --></code></div><!-- END code_close --> + +<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open --> +<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close --> + +<!-- BEGIN b_open --><script><!-- END b_open --> +<!-- BEGIN b_close --></script><!-- END b_close --> + +<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open --> +<!-- BEGIN u_close --></span><!-- END u_close --> + +<!-- BEGIN i_open --><em><!-- END i_open --> +<!-- BEGIN i_close --></em><!-- END i_close --> + +<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color --> + +<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size --> + +<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img --> + +<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url --> + +<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email --> + +<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash --> diff --git a/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml b/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml new file mode 100644 index 0000000000..55a2e689b6 --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bbcodes"> + <column>bbcode_id</column> + <column>bbcode_tag</column> + <column>bbcode_helpline</column> + <column>display_on_posting</column> + <column>bbcode_match</column> + <column>bbcode_tpl</column> + <column>first_pass_match</column> + <column>first_pass_replace</column> + <column>second_pass_match</column> + <column>second_pass_replace</column> + + <row> + <value>13</value> + <value>xss=</value> + <value></value> + <value>1</value> + <value>[xss={TEXT1}]{TEXT2}[/xss]</value> + <value><![CDATA[<a href="{TEXT1}">{TEXT2}</a>]]></value> + <value><\[/xss\]!ies]]></value> + <value><![CDATA['[xss='.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${1}')).':$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', ''', '(', ')'), trim('${2}')).'[/xss:$uid]']]></value> + <value><\[/xss:$uid\]!s]]></value> + <value><![CDATA[<a href="${1}">${2}</a>]]></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/fixtures/unsafe_default_bbcodes.xml b/tests/text_formatter/s9e/fixtures/unsafe_default_bbcodes.xml new file mode 100644 index 0000000000..06524a13cc --- /dev/null +++ b/tests/text_formatter/s9e/fixtures/unsafe_default_bbcodes.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_styles"> + <column>style_id</column> + <column>style_name</column> + <column>style_copyright</column> + <column>style_active</column> + <column>style_path</column> + <column>bbcode_bitfield</column> + <column>style_parent_id</column> + <column>style_parent_tree</column> + + <row> + <value>1</value> + <value>unsafe</value> + <value></value> + <value>1</value> + <value>unsafe</value> + <value>QA==</value> + <value>0</value> + <value></value> + </row> + </table> +</dataset> diff --git a/tests/text_formatter/s9e/link_helper_test.php b/tests/text_formatter/s9e/link_helper_test.php new file mode 100644 index 0000000000..762d67f883 --- /dev/null +++ b/tests/text_formatter/s9e/link_helper_test.php @@ -0,0 +1,35 @@ +<?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_textformatter_s9e_link_helper_test extends phpbb_test_case +{ + public function test_does_not_override_autoimage() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $configurator = $container->get('text_formatter.s9e.factory')->get_configurator(); + + $configurator->Autoimage; + extract($configurator->finalize()); + + $original = 'http://localhost/path_to_long_image_filename_0123456789.png'; + $expected = '<r> + <URL url="http://localhost/path_to_long_image_filename_0123456789.png"> + <IMG src="http://localhost/path_to_long_image_filename_0123456789.png"> + <LINK_TEXT text="http://localhost/path_to_long_image_fil ... 456789.png">http://localhost/path_to_long_image_filename_0123456789.png</LINK_TEXT> + </IMG> + </URL> + </r>'; + + $this->assertXmlStringEqualsXmlString($expected, $parser->parse($original)); + } +} diff --git a/tests/text_formatter/s9e/parser_test.php b/tests/text_formatter/s9e/parser_test.php new file mode 100644 index 0000000000..4b9bbf9bb2 --- /dev/null +++ b/tests/text_formatter/s9e/parser_test.php @@ -0,0 +1,258 @@ +<?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_textformatter_s9e_parser_test extends phpbb_test_case +{ + public function test_load_from_cache() + { + $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser') + ->disableOriginalConstructor() + ->getMock(); + + $cache = $this->getMock('phpbb_mock_cache'); + $cache->expects($this->once()) + ->method('get') + ->with('_foo_parser') + ->will($this->returnValue($mock)); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->never())->method('regenerate'); + + $parser = new \phpbb\textformatter\s9e\parser( + $cache, + '_foo_parser', + $factory, + new phpbb_mock_event_dispatcher + ); + } + + public function test_use_from_cache() + { + $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser') + ->disableOriginalConstructor() + ->getMock(); + + $mock->expects($this->once()) + ->method('parse') + ->with('test') + ->will($this->returnValue('<t>test</t>')); + + $cache = new phpbb_mock_cache; + $cache->put('_foo_parser', $mock); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->never())->method('regenerate'); + + $parser = new \phpbb\textformatter\s9e\parser( + $cache, + '_foo_parser', + $factory, + new phpbb_mock_event_dispatcher + ); + + $this->assertSame('<t>test</t>', $parser->parse('test')); + } + + public function test_regenerate_on_cache_miss() + { + $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser') + ->disableOriginalConstructor() + ->getMock(); + + $mock->expects($this->once()) + ->method('parse') + ->with('test') + ->will($this->returnValue('<t>test</t>')); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->once()) + ->method('regenerate') + ->will($this->returnValue(array('parser' => $mock))); + + $parser = new \phpbb\textformatter\s9e\parser( + new phpbb_mock_cache, + '_foo_parser', + $factory, + new phpbb_mock_event_dispatcher + ); + + $this->assertSame('<t>test</t>', $parser->parse('test')); + } + + /** + * @dataProvider get_options_tests() + */ + public function test_options($adapter_method, $adapter_arg, $concrete_method, $concrete_arg) + { + $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser') + ->setMethods(array($concrete_method)) + ->disableOriginalConstructor() + ->getMock(); + foreach ((array) $concrete_arg as $i => $concrete_arg) + { + $mock->expects($this->at($i)) + ->method($concrete_method) + ->with($concrete_arg); + } + + $cache = new phpbb_mock_cache; + $cache->put('_foo_parser', $mock); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + + $parser = new \phpbb\textformatter\s9e\parser( + $cache, + '_foo_parser', + $factory, + new phpbb_mock_event_dispatcher + ); + + call_user_func_array(array($parser, $adapter_method), (array) $adapter_arg); + } + + public function get_options_tests() + { + return array( + array( + 'disable_bbcode', 'url', + 'disableTag', 'URL' + ), + array( + 'disable_bbcodes', null, + 'disablePlugin', 'BBCodes' + ), + array( + 'disable_magic_url', null, + 'disablePlugin', array('Autoemail', 'Autolink') + ), + array( + 'disable_smilies', null, + 'disablePlugin', 'Emoticons' + ), + array( + 'enable_bbcode', 'url', + 'enableTag', 'URL' + ), + array( + 'enable_bbcodes', null, + 'enablePlugin', 'BBCodes' + ), + array( + 'enable_magic_url', null, + 'enablePlugin', array('Autoemail', 'Autolink') + ), + array( + 'enable_smilies', null, + 'enablePlugin', 'Emoticons' + ) + ); + } + + /** + * @testdox The constructor triggers a core.text_formatter_s9e_parser_setup event + */ + public function test_setup_event() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $dispatcher + ->expects($this->once()) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_parser_setup', + $this->callback(array($this, 'setup_event_callback')) + ) + ->will($this->returnArgument(1)); + + new \phpbb\textformatter\s9e\parser( + $container->get('cache.driver'), + '_foo_parser', + $container->get('text_formatter.s9e.factory'), + $dispatcher + ); + } + + public function setup_event_callback($vars) + { + return isset($vars['parser']) + && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser; + } + + /** + * @testdox parse() triggers a core.text_formatter_s9e_parse_before and core.text_formatter_s9e_parse_after events + */ + public function test_parse_event() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $dispatcher + ->expects($this->any()) + ->method('trigger_event') + ->will($this->returnArgument(1)); + $dispatcher + ->expects($this->at(1)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_parse_before', + $this->callback(array($this, 'parse_before_event_callback')) + ) + ->will($this->returnArgument(1)); + $dispatcher + ->expects($this->at(2)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_parse_after', + $this->callback(array($this, 'parse_after_event_callback')) + ) + ->will($this->returnArgument(1)); + + $parser = new \phpbb\textformatter\s9e\parser( + $container->get('cache.driver'), + '_foo_parser', + $container->get('text_formatter.s9e.factory'), + $dispatcher + ); + $parser->parse('...'); + } + + public function parse_before_event_callback($vars) + { + return isset($vars['parser']) + && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser + && isset($vars['text']) + && $vars['text'] === '...'; + } + + public function parse_after_event_callback($vars) + { + return isset($vars['parser']) + && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser + && isset($vars['xml']) + && $vars['xml'] === '<t>...</t>'; + } + + public function test_get_parser() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $parser = $container->get('text_formatter.parser'); + $this->assertInstanceOf('s9e\\TextFormatter\\Parser', $parser->get_parser()); + } +} diff --git a/tests/text_formatter/s9e/renderer_test.php b/tests/text_formatter/s9e/renderer_test.php new file mode 100644 index 0000000000..175b90fdc7 --- /dev/null +++ b/tests/text_formatter/s9e/renderer_test.php @@ -0,0 +1,481 @@ +<?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_textformatter_s9e_renderer_test extends phpbb_test_case +{ + public function get_cache_dir() + { + return __DIR__ . '/../../tmp/'; + } + + public function test_load_from_cache() + { + // Save a fake renderer class in the cache dir + file_put_contents( + $this->get_cache_dir() . 'renderer_foo.php', + '<?php class renderer_foo { public function setParameter() {} }' + ); + + $cache = $this->getMock('phpbb_mock_cache'); + $cache->expects($this->once()) + ->method('get') + ->with('_foo_renderer') + ->will($this->returnValue(array('class' => 'renderer_foo'))); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->never())->method('regenerate'); + + $renderer = new \phpbb\textformatter\s9e\renderer( + $cache, + $this->get_cache_dir(), + '_foo_renderer', + $factory, + new phpbb_mock_event_dispatcher + ); + } + + public function test_regenerate_on_cache_miss() + { + $mock = $this->getMockForAbstractClass('s9e\\TextFormatter\\Renderer'); + + $cache = $this->getMock('phpbb_mock_cache'); + $cache->expects($this->once()) + ->method('get') + ->with('_foo_renderer') + ->will($this->returnValue(false)); + + $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory') + ->disableOriginalConstructor() + ->getMock(); + $factory->expects($this->once()) + ->method('regenerate') + ->will($this->returnValue(array('parser' => $mock))); + + $renderer = new \phpbb\textformatter\s9e\renderer( + $cache, + $this->get_cache_dir(), + '_foo_renderer', + $factory, + new phpbb_mock_event_dispatcher + ); + } + + /** + * @dataProvider get_options_cases + */ + public function test_options($original, $expected, $calls) + { + $container = new phpbb_mock_container_builder; + $this->get_test_case_helpers()->set_s9e_services($container); + + $renderer = $container->get('text_formatter.renderer'); + + foreach ($calls as $method => $arg) + { + $renderer->$method($arg); + } + + $this->assertSame($expected, $renderer->render($original)); + } + + public function get_options_cases() + { + return array( + array( + '<t>apple</t>', + 'banana', + array('set_viewcensors' => true) + ), + array( + '<t>apple</t>', + 'apple', + array('set_viewcensors' => false) + ), + array( + '<r><FLASH height="456" url="http://example.org/foo.swf" width="123"><s>[flash=123,456]</s><URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL><e>[/flash]</e></FLASH></r>', + '<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="123" height="456"><param name="movie" value="http://example.org/foo.swf"><param name="play" value="false"><param name="loop" value="false"><param name="quality" value="high"><param name="allowScriptAccess" value="never"><param name="allowNetworking" value="internal"><embed src="http://example.org/foo.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="123" height="456" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></object>', + array('set_viewflash' => true) + ), + array( + '<r><IMG src="http://example.org/foo.png"><s>[img]</s>http://example.org/foo.png<e>[/img]</e></IMG></r>', + '<img src="http://example.org/foo.png" class="postimage" alt="Image">', + array('set_viewimg' => true) + ), + array( + '<r><E>:)</E></r>', + '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile">', + array('set_viewsmilies' => true) + ), + array( + '<r><E>:)</E></r>', + ':)', + array('set_viewsmilies' => false) + ), + ); + } + + /** + * @dataProvider get_default_options_cases + */ + public function test_default_options($original, $expected, $setup = null) + { + $container = new phpbb_mock_container_builder; + + if (isset($setup)) + { + $setup($container, $this); + } + + $this->get_test_case_helpers()->set_s9e_services($container); + + $this->assertSame($expected, $container->get('text_formatter.renderer')->render($original)); + } + + public function get_default_options_cases() + { + return array( + array( + '<t>apple</t>', + 'banana' + ), + array( + '<t>apple</t>', + 'banana', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewcensors', false); + + $phpbb_container->set('user', $user); + } + ), + array( + '<t>apple</t>', + 'banana', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewcensors', false); + + $config = new \phpbb\config\config(array('allow_nocensors' => true)); + + $phpbb_container->set('user', $user); + $phpbb_container->set('config', $config); + } + ), + array( + '<t>apple</t>', + 'apple', + function ($phpbb_container, $test) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewcensors', false); + + $config = new \phpbb\config\config(array('allow_nocensors' => true)); + + $auth = $test->getMock('phpbb\\auth\\auth'); + $auth->expects($test->any()) + ->method('acl_get') + ->with('u_chgcensors') + ->will($test->returnValue(true)); + + $phpbb_container->set('user', $user); + $phpbb_container->set('config', $config); + $phpbb_container->set('auth', $auth); + } + ), + array( + '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>', + '<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="123" height="456"><param name="movie" value="http://localhost/foo.swf"><param name="play" value="false"><param name="loop" value="false"><param name="quality" value="high"><param name="allowScriptAccess" value="never"><param name="allowNetworking" value="internal"><embed src="http://localhost/foo.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="123" height="456" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></object>' + ), + array( + '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>', + 'http://localhost/foo.swf', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewflash', false); + + $phpbb_container->set('user', $user); + } + ), + array( + '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>', + '<img src="http://localhost/mrgreen.gif" class="postimage" alt="Image">' + ), + array( + '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>', + '<a href="http://localhost/mrgreen.gif" class="postlink">http://localhost/mrgreen.gif</a>', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('viewimg', false); + + $phpbb_container->set('user', $user); + } + ), + array( + '<r><E>:)</E></r>', + '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile">' + ), + array( + '<r><E>:)</E></r>', + ':)', + function ($phpbb_container) + { + global $phpbb_root_path, $phpEx; + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->optionset('smilies', false); + + $phpbb_container->set('user', $user); + } + ), + ); + } + + public function test_default_lang() + { + global $phpbb_container; + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/default_lang.xml'); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + + $this->assertSame('FOO_BAR', $renderer->render('<r><FOO/></r>')); + } + + /** + * @dataProvider get_option_names + */ + public function test_get_option($option_name) + { + global $phpbb_container; + $this->get_test_case_helpers()->set_s9e_services(); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + + $renderer->{'set_' . $option_name}(false); + $this->assertFalse($renderer->{'get_' . $option_name}()); + $renderer->{'set_' . $option_name}(true); + $this->assertTrue($renderer->{'get_' . $option_name}()); + } + + public function get_option_names() + { + return array( + array('viewcensors'), + array('viewflash'), + array('viewimg'), + array('viewsmilies') + ); + } + + public function test_styles() + { + global $phpbb_container; + + $tests = array( + 1 => '<strong>bold</strong>', + 2 => '<b>bold</b>' + ); + + global $phpbb_root_path, $phpEx; + + foreach ($tests as $style_id => $expected) + { + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->style = array('style_id' => $style_id); + + $phpbb_container = new phpbb_mock_container_builder; + $phpbb_container->set('user', $user); + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/styles.xml', __DIR__ . '/fixtures/styles/'); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + $this->assertSame( + $expected, + $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>') + ); + } + } + + public function test_style_inheritance1() + { + global $phpbb_container, $phpbb_root_path, $phpEx; + + // Style 3 inherits from 2 which inherits from 1. Only style 1 has a bbcode.html + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->style = array('style_id' => 3); + + $phpbb_container = new phpbb_mock_container_builder; + $phpbb_container->set('user', $user); + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/style_inheritance.xml', __DIR__ . '/fixtures/styles/'); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + $this->assertSame( + '<strong>bold</strong>', + $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>') + ); + } + + public function test_style_inheritance2() + { + global $phpbb_container, $phpbb_root_path, $phpEx; + + // Style 5 inherits from 4, but both have a bbcode.html + $tests = array( + 4 => '<b>bold</b>', + 5 => '<b class="barplus">bold</b>' + ); + + foreach ($tests as $style_id => $expected) + { + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $user->style = array('style_id' => $style_id); + + $phpbb_container = new phpbb_mock_container_builder; + $phpbb_container->set('user', $user); + + $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/style_inheritance.xml', __DIR__ . '/fixtures/styles/'); + + $renderer = $phpbb_container->get('text_formatter.renderer'); + $this->assertSame( + $expected, + $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>') + ); + } + } + + /** + * @testdox The constructor triggers a core.text_formatter_s9e_renderer_setup event + */ + public function test_setup_event() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $dispatcher + ->expects($this->once()) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_renderer_setup', + $this->callback(array($this, 'setup_event_callback')) + ) + ->will($this->returnArgument(1)); + + new \phpbb\textformatter\s9e\renderer( + $container->get('cache.driver'), + $container->getParameter('cache.dir'), + '_foo_renderer', + $container->get('text_formatter.s9e.factory'), + $dispatcher + ); + } + + public function setup_event_callback($vars) + { + return isset($vars['renderer']) + && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer; + } + + /** + * @testdox render() triggers a core.text_formatter_s9e_render_before and core.text_formatter_s9e_render_after events + */ + public function test_render_event() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface'); + $dispatcher + ->expects($this->any()) + ->method('trigger_event') + ->will($this->returnArgument(1)); + $dispatcher + ->expects($this->at(1)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_render_before', + $this->callback(array($this, 'render_before_event_callback')) + ) + ->will($this->returnArgument(1)); + $dispatcher + ->expects($this->at(2)) + ->method('trigger_event') + ->with( + 'core.text_formatter_s9e_render_after', + $this->callback(array($this, 'render_after_event_callback')) + ) + ->will($this->returnArgument(1)); + + $renderer = new \phpbb\textformatter\s9e\renderer( + $container->get('cache.driver'), + $container->getParameter('cache.dir'), + '_foo_renderer', + $container->get('text_formatter.s9e.factory'), + $dispatcher + ); + $renderer->render('<t>...</t>'); + } + + public function render_before_event_callback($vars) + { + return isset($vars['renderer']) + && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer + && isset($vars['xml']) + && $vars['xml'] === '<t>...</t>'; + } + + public function render_after_event_callback($vars) + { + return isset($vars['html']) + && $vars['html'] === '...' + && isset($vars['renderer']) + && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer; + } + + public function test_get_renderer() + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $renderer = $container->get('text_formatter.renderer'); + $this->assertInstanceOf('s9e\\TextFormatter\\Renderer', $renderer->get_renderer()); + } +} diff --git a/tests/text_formatter/s9e/utils_test.php b/tests/text_formatter/s9e/utils_test.php new file mode 100644 index 0000000000..719d3cda88 --- /dev/null +++ b/tests/text_formatter/s9e/utils_test.php @@ -0,0 +1,276 @@ +<?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_textformatter_s9e_utils_test extends phpbb_test_case +{ + /** + * @dataProvider get_unparse_tests + */ + public function test_unparse($original, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $utils = $container->get('text_formatter.utils'); + + $this->assertSame($expected, $utils->unparse($original)); + } + + public function get_unparse_tests() + { + return array( + array( + '<t>Plain text</t>', + 'Plain text' + ), + array( + "<t>Multi<br/>\nline</t>", + "Multi\nline" + ), + array( + '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>', + '[b]bold[/b]' + ) + ); + } + + /** + * @dataProvider get_clean_formatting_tests + */ + public function test_clean_formatting($original, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $utils = $container->get('text_formatter.utils'); + + $this->assertSame($expected, $utils->clean_formatting($original)); + } + + public function get_clean_formatting_tests() + { + return array( + array( + '<t>Plain text</t>', + 'Plain text' + ), + array( + "<t>Multi<br/>\nline</t>", + "Multi\nline" + ), + array( + '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>', + ' bold ' + ) + ); + } + + /** + * @dataProvider get_outermost_quote_authors_tests + */ + public function test_get_outermost_quote_authors($original, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $utils = $container->get('text_formatter.utils'); + $parser = $container->get('text_formatter.parser'); + + $this->assertSame($expected, $utils->get_outermost_quote_authors($parser->parse($original))); + } + + public function get_outermost_quote_authors_tests() + { + return array( + array( + 'No quotes here', + array() + ), + array( + '[quote="foo"]..[/quote] [quote]..[/quote]', + array('foo') + ), + array( + '[quote=foo]..[/quote] [quote]..[/quote]', + array('foo') + ), + array( + '[quote=foo]..[/quote] [quote=bar]..[/quote]', + array('foo', 'bar') + ), + array( + '[quote=foo].[quote=baz]..[/quote].[/quote] [quote=bar]..[/quote]', + array('foo', 'bar') + ), + ); + } + + /** + * @dataProvider get_generate_quote_tests + */ + public function test_generate_quote($text, $params, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $utils = $container->get('text_formatter.utils'); + + $this->assertSame($expected, $utils->generate_quote($text, $params)); + } + + public function get_generate_quote_tests() + { + return array( + array( + '...', + array(), + '[quote]...[/quote]', + ), + array( + '...', + array('author' => 'Brian Kibler'), + '[quote="Brian Kibler"]...[/quote]', + ), + array( + '...', + array('author' => 'Brian "Brian Kibler" Kibler of Brian Kibler Gaming'), + '[quote=\'Brian "Brian Kibler" Kibler of Brian Kibler Gaming\']...[/quote]', + ), + array( + '...', + array('author' => "Brian Kibler Gaming's Brian Kibler"), + '[quote="Brian Kibler Gaming\'s Brian Kibler"]...[/quote]', + ), + array( + '...', + array('author' => "\\\"'"), + '[quote="\\\\\\"\'"]...[/quote]', + ), + array( + '...', + array('author' => 'Lots of doubles """ one single \' one backslash \\'), + '[quote=\'Lots of doubles """ one single \\\' one backslash \\\\\']...[/quote]', + ), + array( + '...', + array('author' => "Lots of singles ''' one double \" one backslash \\"), + '[quote="Lots of singles \'\'\' one double \\" one backslash \\\\"]...[/quote]', + ), + array( + '...', + array('author' => 'Defaults to doublequotes """\'\'\''), + '[quote="Defaults to doublequotes \\"\\"\\"\'\'\'"]...[/quote]', + ), + array( + '...', + array( + 'author' => 'user', + 'post_id' => 123, + 'url' => 'http://example.org' + ), + '[quote=user post_id=123 url=http://example.org]...[/quote]', + ), + array( + '...', + array( + 'author' => 'user', + 'post_id' => 123, + 'user_id' => ANONYMOUS + ), + '[quote=user post_id=123]...[/quote]', + ), + array( + '...', + array('author' => ' '), + '[quote=" "]...[/quote]', + ), + array( + '...', + array('author' => 'foo bar'), + '[quote="foo bar"]...[/quote]', + ), + array( + '...', + array('author' => '\\'), + '[quote="\\\\"]...[/quote]', + ), + array( + '...', + array('author' => '[quote="foo"]'), + '[quote=\'[quote="foo"]\']...[/quote]', + ), + array( + '...', + array('author' => '""'), + '[quote=\'""\']...[/quote]', + ), + array( + '...', + array('author' => "''"), + '[quote="\'\'"]...[/quote]', + ), + array( + 'This is a long quote that is definitely going to exceed 80 characters', + array(), + "[quote]\nThis is a long quote that is definitely going to exceed 80 characters\n[/quote]", + ), + array( + ' This is a short quote on its own line ', + array(), + '[quote]This is a short quote on its own line[/quote]', + ), + array( + "This is a short quote\non two lines", + array(), + "[quote]\nThis is a short quote\non two lines\n[/quote]", + ), + ); + } + + /** + * @dataProvider get_remove_bbcode_tests + */ + public function test_remove_bbcode($original, $name, $depth, $expected) + { + $container = $this->get_test_case_helpers()->set_s9e_services(); + $parser = $container->get('text_formatter.parser'); + $utils = $container->get('text_formatter.utils'); + + $parsed = $parser->parse($original); + $actual = $utils->unparse($utils->remove_bbcode($parsed, $name, $depth)); + + $this->assertSame($expected, $actual); + } + + public function get_remove_bbcode_tests() + { + return array( + array( + 'Plain text', + 'b', + 1, + 'Plain text' + ), + array( + '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]', + 'quote', + 0, + '[b]bold[/b]', + ), + array( + '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]', + 'quote', + 1, + '[quote="u0"]q0[/quote][b]bold[/b]', + ), + array( + '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]', + 'quote', + 2, + '[quote="u0"][quote="u1"]q1[/quote]q0[/quote][b]bold[/b]', + ), + ); + } +} |