diff options
Diffstat (limited to 'lib/htmlpurifier/tests/HTMLPurifier/Strategy')
20 files changed, 1708 insertions, 0 deletions
diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/CompositeTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/CompositeTest.php new file mode 100644 index 000000000..8be422cc9 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/CompositeTest.php @@ -0,0 +1,66 @@ +<?php + +class HTMLPurifier_Strategy_Composite_Test + extends HTMLPurifier_Strategy_Composite +{ + + public function __construct(&$strategies) { + $this->strategies =& $strategies; + } + +} + +// doesn't use Strategy harness +class HTMLPurifier_Strategy_CompositeTest extends HTMLPurifier_Harness +{ + + function test() { + + generate_mock_once('HTMLPurifier_Strategy'); + generate_mock_once('HTMLPurifier_Config'); + generate_mock_once('HTMLPurifier_Context'); + + // setup a bunch of mock strategies to inject into our composite test + + $mock_1 = new HTMLPurifier_StrategyMock(); + $mock_2 = new HTMLPurifier_StrategyMock(); + $mock_3 = new HTMLPurifier_StrategyMock(); + + // setup the object + + $strategies = array(&$mock_1, &$mock_2, &$mock_3); + $composite = new HTMLPurifier_Strategy_Composite_Test($strategies); + + // setup expectations + + $input_1 = 'This is raw data'; + $input_2 = 'Processed by 1'; + $input_3 = 'Processed by 1 and 2'; + $input_4 = 'Processed by 1, 2 and 3'; // expected output + + $config = new HTMLPurifier_ConfigMock(); + $context = new HTMLPurifier_ContextMock(); + + $params_1 = array($input_1, $config, $context); + $params_2 = array($input_2, $config, $context); + $params_3 = array($input_3, $config, $context); + + $mock_1->expectOnce('execute', $params_1); + $mock_1->setReturnValue('execute', $input_2, $params_1); + + $mock_2->expectOnce('execute', $params_2); + $mock_2->setReturnValue('execute', $input_3, $params_2); + + $mock_3->expectOnce('execute', $params_3); + $mock_3->setReturnValue('execute', $input_4, $params_3); + + // perform test + + $output = $composite->execute($input_1, $config, $context); + $this->assertIdentical($input_4, $output); + + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/CoreTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/CoreTest.php new file mode 100644 index 000000000..9bca5f60a --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/CoreTest.php @@ -0,0 +1,45 @@ +<?php + +class HTMLPurifier_Strategy_CoreTest extends HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_Core(); + } + + function testBlankInput() { + $this->assertResult(''); + } + + function testMakeWellFormed() { + $this->assertResult( + '<b>Make well formed.', + '<b>Make well formed.</b>' + ); + } + + function testFixNesting() { + $this->assertResult( + '<b><div>Fix nesting.</div></b>', + '<b></b><div><b>Fix nesting.</b></div><b></b>' + ); + } + + function testRemoveForeignElements() { + $this->assertResult( + '<asdf>Foreign element removal.</asdf>', + 'Foreign element removal.' + ); + } + + function testFirstThree() { + $this->assertResult( + '<foo><b><div>All three.</div></b>', + '<b></b><div><b>All three.</b></div><b></b>' + ); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ErrorsHarness.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ErrorsHarness.php new file mode 100644 index 000000000..0e1bca681 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ErrorsHarness.php @@ -0,0 +1,18 @@ +<?php + +class HTMLPurifier_Strategy_ErrorsHarness extends HTMLPurifier_ErrorsHarness +{ + + // needs to be defined + protected function getStrategy() {} + + protected function invoke($input) { + $strategy = $this->getStrategy(); + $lexer = new HTMLPurifier_Lexer_DirectLex(); + $tokens = $lexer->tokenizeHTML($input, $this->config, $this->context); + $strategy->execute($tokens, $this->config, $this->context); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/FixNestingTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/FixNestingTest.php new file mode 100644 index 000000000..9394352ec --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/FixNestingTest.php @@ -0,0 +1,144 @@ +<?php + +class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_FixNesting(); + } + + function testPreserveInlineInRoot() { + $this->assertResult('<b>Bold text</b>'); + } + + function testPreserveInlineAndBlockInRoot() { + $this->assertResult('<a href="about:blank">Blank</a><div>Block</div>'); + } + + function testRemoveBlockInInline() { + $this->assertResult( + '<b><div>Illegal div.</div></b>', + '<b>Illegal div.</b>' + ); + } + + function testEscapeBlockInInline() { + $this->config->set('Core.EscapeInvalidChildren', true); + $this->assertResult( + '<b><div>Illegal div.</div></b>', + '<b><div>Illegal div.</div></b>' + ); + } + + function testRemoveNodeWithMissingRequiredElements() { + $this->assertResult('<ul></ul>', ''); + } + + function testListHandleIllegalPCDATA() { + $this->assertResult( + '<ul>Illegal text<li>Legal item</li></ul>', + '<ul><li>Illegal text</li><li>Legal item</li></ul>' + ); + } + + function testRemoveIllegalPCDATA() { + $this->assertResult( + '<table><tr>Illegal text<td></td></tr></table>', + '<table><tr><td></td></tr></table>' + ); + } + + function testCustomTableDefinition() { + $this->assertResult('<table><tr><td>Cell 1</td></tr></table>'); + } + + function testRemoveEmptyTable() { + $this->assertResult('<table></table>', ''); + } + + function testChameleonRemoveBlockInNodeInInline() { + $this->assertResult( + '<span><ins><div>Not allowed!</div></ins></span>', + '<span><ins>Not allowed!</ins></span>' + ); + } + + function testChameleonRemoveBlockInBlockNodeWithInlineContent() { + $this->assertResult( + '<h1><ins><div>Not allowed!</div></ins></h1>', + '<h1><ins>Not allowed!</ins></h1>' + ); + } + + function testNestedChameleonRemoveBlockInNodeWithInlineContent() { + $this->assertResult( + '<h1><ins><del><div>Not allowed!</div></del></ins></h1>', + '<h1><ins><del>Not allowed!</del></ins></h1>' + ); + } + + function testNestedChameleonPreserveBlockInBlock() { + $this->assertResult( + '<div><ins><del><div>Allowed!</div></del></ins></div>' + ); + } + + function testChameleonEscapeInvalidBlockInInline() { + $this->config->set('Core.EscapeInvalidChildren', true); + $this->assertResult( // alt config + '<span><ins><div>Not allowed!</div></ins></span>', + '<span><ins><div>Not allowed!</div></ins></span>' + ); + } + + function testExclusionsIntegration() { + // test exclusions + $this->assertResult( + '<a><span><a>Not allowed</a></span></a>', + '<a><span></span></a>' + ); + } + + function testPreserveInlineNodeInInlineRootNode() { + $this->config->set('HTML.Parent', 'span'); + $this->assertResult('<b>Bold</b>'); + } + + function testRemoveBlockNodeInInlineRootNode() { + $this->config->set('HTML.Parent', 'span'); + $this->assertResult('<div>Reject</div>', 'Reject'); + } + + function testInvalidParentError() { + // test fallback to div + $this->config->set('HTML.Parent', 'obviously-impossible'); + $this->config->set('Cache.DefinitionImpl', null); + $this->expectError('Cannot use unrecognized element as parent'); + $this->assertResult('<div>Accept</div>'); + } + + function testCascadingRemovalOfNodesMissingRequiredChildren() { + $this->assertResult('<table><tr></tr></table>', ''); + } + + function testCascadingRemovalSpecialCaseCannotScrollOneBack() { + $this->assertResult('<table><tr></tr><tr></tr></table>', ''); + } + + function testLotsOfCascadingRemovalOfNodes() { + $this->assertResult('<table><tbody><tr></tr><tr></tr></tbody><tr></tr><tr></tr></table>', ''); + } + + function testAdjacentRemovalOfNodeMissingRequiredChildren() { + $this->assertResult('<table></table><table></table>', ''); + } + + function testStrictBlockquoteInHTML401() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); + $this->assertResult('<blockquote>text</blockquote>', '<blockquote><p>text</p></blockquote>'); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/FixNesting_ErrorsTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/FixNesting_ErrorsTest.php new file mode 100644 index 000000000..468480774 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/FixNesting_ErrorsTest.php @@ -0,0 +1,41 @@ +<?php + +class HTMLPurifier_Strategy_FixNesting_ErrorsTest extends HTMLPurifier_Strategy_ErrorsHarness +{ + + protected function getStrategy() { + return new HTMLPurifier_Strategy_FixNesting(); + } + + function testNodeRemoved() { + $this->expectErrorCollection(E_ERROR, 'Strategy_FixNesting: Node removed'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('ul', array(), 1)); + $this->invoke('<ul></ul>'); + } + + function testNodeExcluded() { + $this->expectErrorCollection(E_ERROR, 'Strategy_FixNesting: Node excluded'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('a', array(), 2)); + $this->invoke("<a>\n<a></a></a>"); + } + + function testNodeReorganized() { + $this->expectErrorCollection(E_WARNING, 'Strategy_FixNesting: Node reorganized'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('span', array(), 1)); + $this->invoke("<span>Valid<div>Invalid</div></span>"); + } + + function testNoNodeReorganizedForEmptyNode() { + $this->expectNoErrorCollection(); + $this->invoke("<span></span>"); + } + + function testNodeContentsRemoved() { + $this->expectErrorCollection(E_ERROR, 'Strategy_FixNesting: Node contents removed'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('span', array(), 1)); + $this->invoke("<span><div></div></span>"); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjector.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjector.php new file mode 100644 index 000000000..d1724bcb3 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjector.php @@ -0,0 +1,18 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormed_EndInsertInjector extends HTMLPurifier_Injector +{ + public $name = 'EndInsertInjector'; + public $needed = array('span'); + public function handleEnd(&$token) { + if ($token->name == 'div') return; + $token = array( + new HTMLPurifier_Token_Start('b'), + new HTMLPurifier_Token_Text('Comment'), + new HTMLPurifier_Token_End('b'), + $token + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjectorTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjectorTest.php new file mode 100644 index 000000000..72e833b71 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjectorTest.php @@ -0,0 +1,38 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormed_EndInsertInjectorTest extends HTMLPurifier_StrategyHarness +{ + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->config->set('AutoFormat.Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_EndInsertInjector() + )); + } + function testEmpty() { + $this->assertResult(''); + } + function testNormal() { + $this->assertResult('<i>Foo</i>', '<i>Foo<b>Comment</b></i>'); + } + function testEndOfDocumentProcessing() { + $this->assertResult('<i>Foo', '<i>Foo<b>Comment</b></i>'); + } + function testDoubleEndOfDocumentProcessing() { + $this->assertResult('<i><i>Foo', '<i><i>Foo<b>Comment</b></i><b>Comment</b></i>'); + } + function testEndOfNodeProcessing() { + $this->assertResult('<div><i>Foo</div>asdf', '<div><i>Foo<b>Comment</b></i></div><i>asdf<b>Comment</b></i>'); + } + function testEmptyToStartEndProcessing() { + $this->assertResult('<i />', '<i><b>Comment</b></i>'); + } + function testSpuriousEndTag() { + $this->assertResult('</i>', ''); + } + function testLessButStillSpuriousEndTag() { + $this->assertResult('<div></i></div>', '<div></div>'); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjector.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjector.php new file mode 100644 index 000000000..21c491436 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjector.php @@ -0,0 +1,29 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormed_EndRewindInjector extends HTMLPurifier_Injector +{ + public $name = 'EndRewindInjector'; + public $needed = array('span'); + public function handleElement(&$token) { + if (isset($token->_InjectorTest_EndRewindInjector_delete)) { + $token = false; + } + } + public function handleText(&$token) { + $token = false; + } + public function handleEnd(&$token) { + $i = null; + if ( + $this->backward($i, $prev) && + $prev instanceof HTMLPurifier_Token_Start && + $prev->name == 'span' + ) { + $token = false; + $prev->_InjectorTest_EndRewindInjector_delete = true; + $this->rewind($i); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjectorTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjectorTest.php new file mode 100644 index 000000000..96c88748d --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjectorTest.php @@ -0,0 +1,33 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormed_EndRewindInjectorTest extends HTMLPurifier_StrategyHarness +{ + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->config->set('AutoFormat.Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_EndRewindInjector() + )); + } + function testBasic() { + $this->assertResult(''); + } + function testFunction() { + $this->assertResult('<span>asdf</span>',''); + } + function testFailedFunction() { + $this->assertResult('<span>asd<b>asdf</b>asdf</span>','<span><b></b></span>'); + } + function testPadded() { + $this->assertResult('<b></b><span>asdf</span><b></b>','<b></b><b></b>'); + } + function testDoubled() { + $this->config->set('AutoFormat.Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_EndRewindInjector(), + new HTMLPurifier_Strategy_MakeWellFormed_EndRewindInjector(), + )); + $this->assertResult('<b></b><span>asdf</span>', '<b></b>'); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjector.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjector.php new file mode 100644 index 000000000..258346b8d --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjector.php @@ -0,0 +1,12 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormed_SkipInjector extends HTMLPurifier_Injector +{ + public $name = 'EndRewindInjector'; + public $needed = array('span'); + public function handleElement(&$token) { + $token = array(clone $token, clone $token); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjectorTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjectorTest.php new file mode 100644 index 000000000..770b3d84e --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjectorTest.php @@ -0,0 +1,27 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormed_SkipInjectorTest extends HTMLPurifier_StrategyHarness +{ + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->config->set('AutoFormat.Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_SkipInjector() + )); + } + function testEmpty() { + $this->assertResult(''); + } + function testMultiply() { + $this->assertResult('<br />', '<br /><br />'); + } + function testMultiplyMultiply() { + $this->config->set('AutoFormat.Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_SkipInjector(), + new HTMLPurifier_Strategy_MakeWellFormed_SkipInjector() + )); + $this->assertResult('<br />', '<br /><br /><br /><br />'); + } +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormedTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormedTest.php new file mode 100644 index 000000000..c6d775c5a --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormedTest.php @@ -0,0 +1,149 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormedTest extends HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_MakeWellFormed(); + } + + function testEmptyInput() { + $this->assertResult(''); + } + + function testWellFormedInput() { + $this->assertResult('This is <b>bold text</b>.'); + } + + function testUnclosedTagTerminatedByDocumentEnd() { + $this->assertResult( + '<b>Unclosed tag, gasp!', + '<b>Unclosed tag, gasp!</b>' + ); + } + + function testUnclosedTagTerminatedByParentNodeEnd() { + $this->assertResult( + '<b><i>Bold and italic?</b>', + '<b><i>Bold and italic?</i></b><i></i>' + ); + } + + function testRemoveStrayClosingTag() { + $this->assertResult( + 'Unused end tags... recycle!</b>', + 'Unused end tags... recycle!' + ); + } + + function testConvertStartToEmpty() { + $this->assertResult( + '<br style="clear:both;">', + '<br style="clear:both;" />' + ); + } + + function testConvertEmptyToStart() { + $this->assertResult( + '<div style="clear:both;" />', + '<div style="clear:both;"></div>' + ); + } + + function testAutoCloseParagraph() { + $this->assertResult( + '<p>Paragraph 1<p>Paragraph 2', + '<p>Paragraph 1</p><p>Paragraph 2</p>' + ); + } + + function testAutoCloseParagraphInsideDiv() { + $this->assertResult( + '<div><p>Paragraphs<p>In<p>A<p>Div</div>', + '<div><p>Paragraphs</p><p>In</p><p>A</p><p>Div</p></div>' + ); + } + + function testAutoCloseListItem() { + $this->assertResult( + '<ol><li>Item 1<li>Item 2</ol>', + '<ol><li>Item 1</li><li>Item 2</li></ol>' + ); + } + + function testAutoCloseColgroup() { + $this->assertResult( + '<table><colgroup><col /><tr></tr></table>', + '<table><colgroup><col /></colgroup><tr></tr></table>' + ); + } + + function testAutoCloseMultiple() { + $this->assertResult( + '<b><span><div></div>asdf', + '<b><span></span></b><div><b></b></div><b>asdf</b>' + ); + } + + function testUnrecognized() { + $this->assertResult( + '<asdf><foobar /><biddles>foo</asdf>', + '<asdf><foobar /><biddles>foo</biddles></asdf>' + ); + } + + function testBlockquoteWithInline() { + $this->config->set('HTML.Doctype', 'XHTML 1.0 Strict'); + $this->assertResult( + // This is actually invalid, but will be fixed by + // ChildDef_StrictBlockquote + '<blockquote>foo<b>bar</b></blockquote>' + ); + } + + function testLongCarryOver() { + $this->assertResult( + '<b>asdf<div>asdf<i>df</i></div>asdf</b>', + '<b>asdf</b><div><b>asdf<i>df</i></b></div><b>asdf</b>' + ); + } + + function testInterleaved() { + $this->assertResult( + '<u>foo<i>bar</u>baz</i>', + '<u>foo<i>bar</i></u><i>baz</i>' + ); + } + + function testNestedOl() { + $this->assertResult( + '<ol><ol><li>foo</li></ol></ol>', + '<ol><ol><li>foo</li></ol></ol>' + ); + } + + function testNestedUl() { + $this->assertResult( + '<ul><ul><li>foo</li></ul></ul>', + '<ul><ul><li>foo</li></ul></ul>' + ); + } + + function testNestedOlWithStrangeEnding() { + $this->assertResult( + '<ol><li><ol><ol><li>foo</li></ol></li><li>foo</li></ol>', + '<ol><li><ol><ol><li>foo</li></ol></ol></li><li>foo</li></ol>' + ); + } + + function testNoAutocloseIfNoParentsCanAccomodateTag() { + $this->assertResult( + '<table><tr><td><li>foo</li></td></tr></table>', + '<table><tr><td>foo</td></tr></table>' + ); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed_ErrorsTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed_ErrorsTest.php new file mode 100644 index 000000000..e825e2e2a --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed_ErrorsTest.php @@ -0,0 +1,62 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormed_ErrorsTest extends HTMLPurifier_Strategy_ErrorsHarness +{ + + protected function getStrategy() { + return new HTMLPurifier_Strategy_MakeWellFormed(); + } + + function testUnnecessaryEndTagRemoved() { + $this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_End('b', array(), 1, 0)); + $this->invoke('</b>'); + } + + function testUnnecessaryEndTagToText() { + $this->config->set('Core.EscapeInvalidTags', true); + $this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_End('b', array(), 1, 0)); + $this->invoke('</b>'); + } + + function testTagAutoclose() { + $this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', new HTMLPurifier_Token_Start('p', array(), 1, 0)); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('div', array(), 1, 6)); + $this->invoke('<p>Foo<div>Bar</div>'); + } + + function testTagCarryOver() { + $b = new HTMLPurifier_Token_Start('b', array(), 1, 0); + $this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag carryover', $b); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('div', array(), 1, 6)); + $this->invoke('<b>Foo<div>Bar</div>'); + } + + function testStrayEndTagRemoved() { + $this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_End('b', array(), 1, 3)); + $this->invoke('<i></b></i>'); + } + + function testStrayEndTagToText() { + $this->config->set('Core.EscapeInvalidTags', true); + $this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_End('b', array(), 1, 3)); + $this->invoke('<i></b></i>'); + } + + function testTagClosedByElementEnd() { + $this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', new HTMLPurifier_Token_Start('b', array(), 1, 3)); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_End('i', array(), 1, 12)); + $this->invoke('<i><b>Foobar</i>'); + } + + function testTagClosedByDocumentEnd() { + $this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', new HTMLPurifier_Token_Start('b', array(), 1, 0)); + $this->invoke('<b>Foobar'); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed_InjectorTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed_InjectorTest.php new file mode 100644 index 000000000..f0e01340a --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/MakeWellFormed_InjectorTest.php @@ -0,0 +1,149 @@ +<?php + +class HTMLPurifier_Strategy_MakeWellFormed_InjectorTest extends HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->config->set('AutoFormat.AutoParagraph', true); + $this->config->set('AutoFormat.Linkify', true); + $this->config->set('AutoFormat.RemoveEmpty', true); + generate_mock_once('HTMLPurifier_Injector'); + } + + function testEndHandler() { + $mock = new HTMLPurifier_InjectorMock(); + $b = new HTMLPurifier_Token_End('b'); + $b->skip = array(0 => true); + $b->start = new HTMLPurifier_Token_Start('b'); + $b->start->skip = array(0 => true, 1 => true); + $mock->expectAt(0, 'handleEnd', array($b)); + $i = new HTMLPurifier_Token_End('i'); + $i->start = new HTMLPurifier_Token_Start('i'); + $i->skip = array(0 => true); + $i->start->skip = array(0 => true, 1 => true); + $mock->expectAt(1, 'handleEnd', array($i)); + $mock->expectCallCount('handleEnd', 2); + $mock->setReturnValue('getRewind', false); + $this->config->set('AutoFormat.AutoParagraph', false); + $this->config->set('AutoFormat.Linkify', false); + $this->config->set('AutoFormat.Custom', array($mock)); + $this->assertResult('<i><b>asdf</b>', '<i><b>asdf</b></i>'); + } + + function testErrorRequiredElementNotAllowed() { + $this->config->set('HTML.Allowed', ''); + $this->expectError('Cannot enable AutoParagraph injector because p is not allowed'); + $this->expectError('Cannot enable Linkify injector because a is not allowed'); + $this->assertResult('Foobar'); + } + + function testErrorRequiredAttributeNotAllowed() { + $this->config->set('HTML.Allowed', 'a,p'); + $this->expectError('Cannot enable Linkify injector because a.href is not allowed'); + $this->assertResult('<p>http://example.com</p>'); + } + + function testOnlyAutoParagraph() { + $this->assertResult( + 'Foobar', + '<p>Foobar</p>' + ); + } + + function testParagraphWrappingOnlyLink() { + $this->assertResult( + 'http://example.com', + '<p><a href="http://example.com">http://example.com</a></p>' + ); + } + + function testParagraphWrappingNodeContainingLink() { + $this->assertResult( + '<b>http://example.com</b>', + '<p><b><a href="http://example.com">http://example.com</a></b></p>' + ); + } + + function testParagraphWrappingPoorlyFormedNodeContainingLink() { + $this->assertResult( + '<b>http://example.com', + '<p><b><a href="http://example.com">http://example.com</a></b></p>' + ); + } + + function testTwoParagraphsContainingOnlyOneLink() { + $this->assertResult( + "http://example.com\n\nhttp://dev.example.com", +'<p><a href="http://example.com">http://example.com</a></p> + +<p><a href="http://dev.example.com">http://dev.example.com</a></p>' + ); + } + + function testParagraphNextToDivWithLinks() { + $this->assertResult( + 'http://example.com <div>http://example.com</div>', +'<p><a href="http://example.com">http://example.com</a> </p> + +<div><a href="http://example.com">http://example.com</a></div>' + ); + } + + function testRealisticLinkInSentence() { + $this->assertResult( + 'This URL http://example.com is what you need', + '<p>This URL <a href="http://example.com">http://example.com</a> is what you need</p>' + ); + } + + function testParagraphAfterLinkifiedURL() { + $this->assertResult( +"http://google.com + +<b>b</b>", +"<p><a href=\"http://google.com\">http://google.com</a></p> + +<p><b>b</b></p>" + ); + } + + function testEmptyAndParagraph() { + // This is a fairly degenerate case, but it demonstrates that + // the two don't error out together, at least. + // Change this behavior! + $this->assertResult( +"<p>asdf + +asdf<b></b></p> + +<p></p><i></i>", +"<p>asdf</p> + +<p>asdf</p> + +" + ); + } + + function testRewindAndParagraph() { + $this->assertResult( +"bar + +<p><i></i> + +</p> + +foo", +"<p>bar</p> + + + +<p>foo</p>" + ); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElementsTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElementsTest.php new file mode 100644 index 000000000..b3ca1646a --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElementsTest.php @@ -0,0 +1,115 @@ +<?php + +class HTMLPurifier_Strategy_RemoveForeignElementsTest extends HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_RemoveForeignElements(); + } + + function testBlankInput() { + $this->assertResult(''); + } + + function testPreserveRecognizedElements() { + $this->assertResult('This is <b>bold text</b>.'); + } + + function testRemoveForeignElements() { + $this->assertResult( + '<asdf>Bling</asdf><d href="bang">Bong</d><foobar />', + 'BlingBong' + ); + } + + function testRemoveScriptAndContents() { + $this->assertResult( + '<script>alert();</script>', + '' + ); + } + + function testRemoveStyleAndContents() { + $this->assertResult( + '<style>.foo {blink;}</style>', + '' + ); + } + + function testRemoveOnlyScriptTagsLegacy() { + $this->config->set('Core.RemoveScriptContents', false); + $this->assertResult( + '<script>alert();</script>', + 'alert();' + ); + } + + function testRemoveOnlyScriptTags() { + $this->config->set('Core.HiddenElements', array()); + $this->assertResult( + '<script>alert();</script>', + 'alert();' + ); + } + + function testRemoveInvalidImg() { + $this->assertResult('<img />', ''); + } + + function testPreserveValidImg() { + $this->assertResult('<img src="foobar.gif" alt="foobar.gif" />'); + } + + function testPreserveInvalidImgWhenRemovalIsDisabled() { + $this->config->set('Core.RemoveInvalidImg', false); + $this->assertResult('<img />'); + } + + function testTextifyCommentedScriptContents() { + $this->config->set('HTML.Trusted', true); + $this->config->set('Output.CommentScriptContents', false); // simplify output + $this->assertResult( +'<script type="text/javascript"><!-- +alert(<b>bold</b>); +// --></script>', +'<script type="text/javascript"> +alert(<b>bold</b>); +// </script>' + ); + } + + function testRequiredAttributesTestNotPerformedOnEndTag() { + $def = $this->config->getHTMLDefinition(true); + $def->addElement('f', 'Block', 'Optional: #PCDATA', false, array('req*' => 'Text')); + $this->assertResult('<f req="text">Foo</f> Bar'); + } + + function testPreserveCommentsWithHTMLTrusted() { + $this->config->set('HTML.Trusted', true); + $this->assertResult('<!-- foo -->'); + } + + function testRemoveTrailingHyphensInComment() { + $this->config->set('HTML.Trusted', true); + $this->assertResult('<!-- foo ----->', '<!-- foo -->'); + } + + function testCollapseDoubleHyphensInComment() { + $this->config->set('HTML.Trusted', true); + $this->assertResult('<!-- bo --- asdf--as -->', '<!-- bo - asdf-as -->'); + } + + function testPreserveCommentsWithLookup() { + $this->config->set('HTML.AllowedComments', array('allowed')); + $this->assertResult('<!-- allowed --><!-- not allowed -->', '<!-- allowed -->'); + } + + function testPreserveCommentsWithRegexp() { + $this->config->set('HTML.AllowedCommentsRegexp', '/^allowed[1-9]$/'); + $this->assertResult('<!-- allowed1 --><!-- not allowed -->', '<!-- allowed1 -->'); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElements_ErrorsTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElements_ErrorsTest.php new file mode 100644 index 000000000..4b4e31074 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElements_ErrorsTest.php @@ -0,0 +1,71 @@ +<?php + +class HTMLPurifier_Strategy_RemoveForeignElements_ErrorsTest extends HTMLPurifier_Strategy_ErrorsHarness +{ + + public function setup() { + parent::setup(); + $this->config->set('HTML.TidyLevel', 'heavy'); + } + + protected function getStrategy() { + return new HTMLPurifier_Strategy_RemoveForeignElements(); + } + + function testTagTransform() { + $this->expectErrorCollection(E_NOTICE, 'Strategy_RemoveForeignElements: Tag transform', 'center'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('div', array('style' => 'text-align:center;'), 1)); + $this->invoke('<center>'); + } + + function testMissingRequiredAttr() { + // a little fragile, since img has two required attributes + $this->expectErrorCollection(E_ERROR, 'Strategy_RemoveForeignElements: Missing required attribute', 'alt'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Empty('img', array(), 1)); + $this->invoke('<img />'); + } + + function testForeignElementToText() { + $this->config->set('Core.EscapeInvalidTags', true); + $this->expectErrorCollection(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('invalid', array(), 1)); + $this->invoke('<invalid>'); + } + + function testForeignElementRemoved() { + // uses $CurrentToken.Serialized + $this->expectErrorCollection(E_ERROR, 'Strategy_RemoveForeignElements: Foreign element removed'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('invalid', array(), 1)); + $this->invoke('<invalid>'); + } + + function testCommentRemoved() { + $this->expectErrorCollection(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Comment(' test ', 1)); + $this->invoke('<!-- test -->'); + } + + function testTrailingHyphenInCommentRemoved() { + $this->config->set('HTML.Trusted', true); + $this->expectErrorCollection(E_NOTICE, 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Comment(' test ', 1)); + $this->invoke('<!-- test ---->'); + } + + function testDoubleHyphenInCommentRemoved() { + $this->config->set('HTML.Trusted', true); + $this->expectErrorCollection(E_NOTICE, 'Strategy_RemoveForeignElements: Hyphens in comment collapsed'); + $this->expectContext('CurrentToken', new HTMLPurifier_Token_Comment(' test - test - test ', 1)); + $this->invoke('<!-- test --- test -- test -->'); + } + + function testForeignMetaElementRemoved() { + $this->collector->expectAt(0, 'send', array(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed')); + $this->collector->expectContextAt(0, 'CurrentToken', new HTMLPurifier_Token_Start('script', array(), 1)); + $this->collector->expectAt(1, 'send', array(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', 'script')); + $this->invoke('<script>asdf'); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElements_TidyTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElements_TidyTest.php new file mode 100644 index 000000000..22fc456a7 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/RemoveForeignElements_TidyTest.php @@ -0,0 +1,45 @@ +<?php + +class HTMLPurifier_Strategy_RemoveForeignElements_TidyTest + extends HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_RemoveForeignElements(); + $this->config->set('HTML.TidyLevel', 'heavy'); + } + + function testCenterTransform() { + $this->assertResult( + '<center>Look I am Centered!</center>', + '<div style="text-align:center;">Look I am Centered!</div>' + ); + } + + function testFontTransform() { + $this->assertResult( + '<font color="red" face="Arial" size="6">Big Warning!</font>', + '<span style="color:red;font-family:Arial;font-size:xx-large;">Big'. + ' Warning!</span>' + ); + } + + function testTransformToForbiddenElement() { + $this->config->set('HTML.Allowed', 'div'); + $this->assertResult( + '<font color="red" face="Arial" size="6">Big Warning!</font>', + 'Big Warning!' + ); + } + + function testMenuTransform() { + $this->assertResult( + '<menu><li>Item 1</li></menu>', + '<ul><li>Item 1</li></ul>' + ); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributesTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributesTest.php new file mode 100644 index 000000000..5fc86cbda --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributesTest.php @@ -0,0 +1,232 @@ +<?php + +class HTMLPurifier_Strategy_ValidateAttributesTest extends + HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_ValidateAttributes(); + } + + function testEmptyInput() { + $this->assertResult(''); + } + + function testRemoveIDByDefault() { + $this->assertResult( + '<div id="valid">Kill the ID.</div>', + '<div>Kill the ID.</div>' + ); + } + + function testRemoveInvalidDir() { + $this->assertResult( + '<span dir="up-to-down">Bad dir.</span>', + '<span>Bad dir.</span>' + ); + } + + function testPreserveValidClass() { + $this->assertResult('<div class="valid">Valid</div>'); + } + + function testSelectivelyRemoveInvalidClasses() { + $this->config->set('HTML.Doctype', 'XHTML 1.1'); + $this->assertResult( + '<div class="valid 0invalid">Keep valid.</div>', + '<div class="valid">Keep valid.</div>' + ); + } + + function testPreserveTitle() { + $this->assertResult( + '<acronym title="PHP: Hypertext Preprocessor">PHP</acronym>' + ); + } + + function testAddXMLLang() { + $this->assertResult( + '<span lang="fr">La soupe.</span>', + '<span lang="fr" xml:lang="fr">La soupe.</span>' + ); + } + + function testOnlyXMLLangInXHTML11() { + $this->config->set('HTML.Doctype', 'XHTML 1.1'); + $this->assertResult( + '<b lang="en">asdf</b>', + '<b xml:lang="en">asdf</b>' + ); + } + + function testBasicURI() { + $this->assertResult('<a href="http://www.google.com/">Google</a>'); + } + + function testInvalidURI() { + $this->assertResult( + '<a href="javascript:badstuff();">Google</a>', + '<a>Google</a>' + ); + } + + function testBdoAddMissingDir() { + $this->assertResult( + '<bdo>Go left.</bdo>', + '<bdo dir="ltr">Go left.</bdo>' + ); + } + + function testBdoReplaceInvalidDirWithDefault() { + $this->assertResult( + '<bdo dir="blahblah">Invalid value!</bdo>', + '<bdo dir="ltr">Invalid value!</bdo>' + ); + } + + function testBdoAlternateDefaultDir() { + $this->config->set('Attr.DefaultTextDir', 'rtl'); + $this->assertResult( + '<bdo>Go right.</bdo>', + '<bdo dir="rtl">Go right.</bdo>' + ); + } + + function testRemoveDirWhenNotRequired() { + $this->assertResult( + '<span dir="blahblah">Invalid value!</span>', + '<span>Invalid value!</span>' + ); + } + + function testTableAttributes() { + $this->assertResult( +'<table frame="above" rules="rows" summary="A test table" border="2" cellpadding="5%" cellspacing="3" width="100%"> + <col align="right" width="4*" /> + <col charoff="5" align="char" width="*" /> + <tr valign="top"> + <th abbr="name">Fiddly name</th> + <th abbr="price">Super-duper-price</th> + </tr> + <tr> + <td abbr="carrot">Carrot Humungous</td> + <td>$500.23</td> + </tr> + <tr> + <td colspan="2">Taken off the market</td> + </tr> +</table>' + ); + } + + function testColSpanIsNonZero() { + $this->assertResult( + '<col span="0" />', + '<col />' + ); + } + + function testImgAddDefaults() { + $this->config->set('Core.RemoveInvalidImg', false); + $this->assertResult( + '<img />', + '<img src="" alt="Invalid image" />' + ); + } + + function testImgGenerateAlt() { + $this->assertResult( + '<img src="foobar.jpg" />', + '<img src="foobar.jpg" alt="foobar.jpg" />' + ); + } + + function testImgAddDefaultSrc() { + $this->config->set('Core.RemoveInvalidImg', false); + $this->assertResult( + '<img alt="pretty picture" />', + '<img alt="pretty picture" src="" />' + ); + } + + function testImgRemoveNonRetrievableProtocol() { + $this->config->set('Core.RemoveInvalidImg', false); + $this->assertResult( + '<img src="mailto:foo@example.com" />', + '<img alt="mailto:foo@example.com" src="" />' + ); + } + + function testPreserveRel() { + $this->config->set('Attr.AllowedRel', 'nofollow'); + $this->assertResult('<a href="foo" rel="nofollow" />'); + } + + function testPreserveTarget() { + $this->config->set('Attr.AllowedFrameTargets', '_top'); + $this->config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); + $this->assertResult('<a href="foo" target="_top" />'); + } + + function testRemoveTargetWhenNotSupported() { + $this->config->set('HTML.Doctype', 'XHTML 1.0 Strict'); + $this->config->set('Attr.AllowedFrameTargets', '_top'); + $this->assertResult( + '<a href="foo" target="_top" />', + '<a href="foo" />' + ); + } + + function testKeepAbsoluteCSSWidthAndHeightOnImg() { + $this->assertResult( + '<img src="" alt="" style="width:10px;height:10px;border:1px solid #000;" />' + ); + } + + function testRemoveLargeCSSWidthAndHeightOnImg() { + $this->assertResult( + '<img src="" alt="" style="width:10000000px;height:10000000px;border:1px solid #000;" />', + '<img src="" alt="" style="border:1px solid #000;" />' + ); + } + + function testRemoveLargeCSSWidthAndHeightOnImgWithUserConf() { + $this->config->set('CSS.MaxImgLength', '1px'); + $this->assertResult( + '<img src="" alt="" style="width:1mm;height:1mm;border:1px solid #000;" />', + '<img src="" alt="" style="border:1px solid #000;" />' + ); + } + + function testKeepLargeCSSWidthAndHeightOnImgWhenToldTo() { + $this->config->set('CSS.MaxImgLength', null); + $this->assertResult( + '<img src="" alt="" style="width:10000000px;height:10000000px;border:1px solid #000;" />' + ); + } + + function testKeepPercentCSSWidthAndHeightOnImgWhenToldTo() { + $this->config->set('CSS.MaxImgLength', null); + $this->assertResult( + '<img src="" alt="" style="width:100%;height:100%;border:1px solid #000;" />' + ); + } + + function testRemoveRelativeCSSWidthAndHeightOnImg() { + $this->assertResult( + '<img src="" alt="" style="width:10em;height:10em;border:1px solid #000;" />', + '<img src="" alt="" style="border:1px solid #000;" />' + ); + } + + function testRemovePercentCSSWidthAndHeightOnImg() { + $this->assertResult( + '<img src="" alt="" style="width:100%;height:100%;border:1px solid #000;" />', + '<img src="" alt="" style="border:1px solid #000;" />' + ); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributes_IDTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributes_IDTest.php new file mode 100644 index 000000000..c8c750723 --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributes_IDTest.php @@ -0,0 +1,63 @@ +<?php + +class HTMLPurifier_Strategy_ValidateAttributes_IDTest extends HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_ValidateAttributes(); + $this->config->set('Attr.EnableID', true); + } + + + function testPreserveIDWhenEnabled() { + $this->assertResult('<div id="valid">Preserve the ID.</div>'); + } + + function testRemoveInvalidID() { + $this->assertResult( + '<div id="0invalid">Kill the ID.</div>', + '<div>Kill the ID.</div>' + ); + } + + function testRemoveDuplicateID() { + $this->assertResult( + '<div id="valid">Valid</div><div id="valid">Invalid</div>', + '<div id="valid">Valid</div><div>Invalid</div>' + ); + } + + function testAttributeKeyCaseInsensitivity() { + $this->assertResult( + '<div ID="valid">Convert ID to lowercase.</div>', + '<div id="valid">Convert ID to lowercase.</div>' + ); + } + + function testTrimWhitespace() { + $this->assertResult( + '<div id=" valid ">Trim whitespace.</div>', + '<div id="valid">Trim whitespace.</div>' + ); + } + + function testIDBlacklist() { + $this->config->set('Attr.IDBlacklist', array('invalid')); + $this->assertResult( + '<div id="invalid">Invalid</div>', + '<div>Invalid</div>' + ); + } + + function testNameConvertedToID() { + $this->config->set('HTML.TidyLevel', 'heavy'); + $this->assertResult( + '<a name="foobar" />', + '<a id="foobar" />' + ); + } + +} + +// vim: et sw=4 sts=4 diff --git a/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributes_TidyTest.php b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributes_TidyTest.php new file mode 100644 index 000000000..d4eeeebfc --- /dev/null +++ b/lib/htmlpurifier/tests/HTMLPurifier/Strategy/ValidateAttributes_TidyTest.php @@ -0,0 +1,351 @@ +<?php + +class HTMLPurifier_Strategy_ValidateAttributes_TidyTest extends HTMLPurifier_StrategyHarness +{ + + function setUp() { + parent::setUp(); + $this->obj = new HTMLPurifier_Strategy_ValidateAttributes(); + $this->config->set('HTML.TidyLevel', 'heavy'); + } + + function testConvertCenterAlign() { + $this->assertResult( + '<h1 align="center">Centered Headline</h1>', + '<h1 style="text-align:center;">Centered Headline</h1>' + ); + } + + function testConvertRightAlign() { + $this->assertResult( + '<h1 align="right">Right-aligned Headline</h1>', + '<h1 style="text-align:right;">Right-aligned Headline</h1>' + ); + } + + function testConvertLeftAlign() { + $this->assertResult( + '<h1 align="left">Left-aligned Headline</h1>', + '<h1 style="text-align:left;">Left-aligned Headline</h1>' + ); + } + + function testConvertJustifyAlign() { + $this->assertResult( + '<p align="justify">Justified Paragraph</p>', + '<p style="text-align:justify;">Justified Paragraph</p>' + ); + } + + function testRemoveInvalidAlign() { + $this->assertResult( + '<h1 align="invalid">Invalid Headline</h1>', + '<h1>Invalid Headline</h1>' + ); + } + + function testConvertTableLengths() { + $this->assertResult( + '<td width="5%" height="10" /><th width="10" height="5%" /><hr width="10" height="10" />', + '<td style="width:5%;height:10px;" /><th style="width:10px;height:5%;" /><hr style="width:10px;" />' + ); + } + + function testTdConvertNowrap() { + $this->assertResult( + '<td nowrap />', + '<td style="white-space:nowrap;" />' + ); + } + + function testCaptionConvertAlignLeft() { + $this->assertResult( + '<caption align="left" />', + '<caption style="text-align:left;" />' + ); + } + + function testCaptionConvertAlignRight() { + $this->assertResult( + '<caption align="right" />', + '<caption style="text-align:right;" />' + ); + } + + function testCaptionConvertAlignTop() { + $this->assertResult( + '<caption align="top" />', + '<caption style="caption-side:top;" />' + ); + } + + function testCaptionConvertAlignBottom() { + $this->assertResult( + '<caption align="bottom" />', + '<caption style="caption-side:bottom;" />' + ); + } + + function testCaptionRemoveInvalidAlign() { + $this->assertResult( + '<caption align="nonsense" />', + '<caption />' + ); + } + + function testTableConvertAlignLeft() { + $this->assertResult( + '<table align="left" />', + '<table style="float:left;" />' + ); + } + + function testTableConvertAlignCenter() { + $this->assertResult( + '<table align="center" />', + '<table style="margin-left:auto;margin-right:auto;" />' + ); + } + + function testTableConvertAlignRight() { + $this->assertResult( + '<table align="right" />', + '<table style="float:right;" />' + ); + } + + function testTableRemoveInvalidAlign() { + $this->assertResult( + '<table align="top" />', + '<table />' + ); + } + + function testImgConvertAlignLeft() { + $this->assertResult( + '<img src="foobar.jpg" alt="foobar" align="left" />', + '<img src="foobar.jpg" alt="foobar" style="float:left;" />' + ); + } + + function testImgConvertAlignRight() { + $this->assertResult( + '<img src="foobar.jpg" alt="foobar" align="right" />', + '<img src="foobar.jpg" alt="foobar" style="float:right;" />' + ); + } + + function testImgConvertAlignBottom() { + $this->assertResult( + '<img src="foobar.jpg" alt="foobar" align="bottom" />', + '<img src="foobar.jpg" alt="foobar" style="vertical-align:baseline;" />' + ); + } + + function testImgConvertAlignMiddle() { + $this->assertResult( + '<img src="foobar.jpg" alt="foobar" align="middle" />', + '<img src="foobar.jpg" alt="foobar" style="vertical-align:middle;" />' + ); + } + + function testImgConvertAlignTop() { + $this->assertResult( + '<img src="foobar.jpg" alt="foobar" align="top" />', + '<img src="foobar.jpg" alt="foobar" style="vertical-align:top;" />' + ); + } + + function testImgRemoveInvalidAlign() { + $this->assertResult( + '<img src="foobar.jpg" alt="foobar" align="outerspace" />', + '<img src="foobar.jpg" alt="foobar" />' + ); + } + + function testBorderConvertHVSpace() { + $this->assertResult( + '<img src="foo" alt="foo" hspace="1" vspace="3" />', + '<img src="foo" alt="foo" style="margin-top:3px;margin-bottom:3px;margin-left:1px;margin-right:1px;" />' + ); + } + + function testHrConvertSize() { + $this->assertResult( + '<hr size="3" />', + '<hr style="height:3px;" />' + ); + } + + function testHrConvertNoshade() { + $this->assertResult( + '<hr noshade />', + '<hr style="color:#808080;background-color:#808080;border:0;" />' + ); + } + + function testHrConvertAlignLeft() { + $this->assertResult( + '<hr align="left" />', + '<hr style="margin-left:0;margin-right:auto;text-align:left;" />' + ); + } + + function testHrConvertAlignCenter() { + $this->assertResult( + '<hr align="center" />', + '<hr style="margin-left:auto;margin-right:auto;text-align:center;" />' + ); + } + + function testHrConvertAlignRight() { + $this->assertResult( + '<hr align="right" />', + '<hr style="margin-left:auto;margin-right:0;text-align:right;" />' + ); + } + + function testHrRemoveInvalidAlign() { + $this->assertResult( + '<hr align="bottom" />', + '<hr />' + ); + } + + function testBrConvertClearLeft() { + $this->assertResult( + '<br clear="left" />', + '<br style="clear:left;" />' + ); + } + + function testBrConvertClearRight() { + $this->assertResult( + '<br clear="right" />', + '<br style="clear:right;" />' + ); + } + + function testBrConvertClearAll() { + $this->assertResult( + '<br clear="all" />', + '<br style="clear:both;" />' + ); + } + + function testBrConvertClearNone() { + $this->assertResult( + '<br clear="none" />', + '<br style="clear:none;" />' + ); + } + + function testBrRemoveInvalidClear() { + $this->assertResult( + '<br clear="foo" />', + '<br />' + ); + } + + function testUlConvertTypeDisc() { + $this->assertResult( + '<ul type="disc" />', + '<ul style="list-style-type:disc;" />' + ); + } + + function testUlConvertTypeSquare() { + $this->assertResult( + '<ul type="square" />', + '<ul style="list-style-type:square;" />' + ); + } + + function testUlConvertTypeCircle() { + $this->assertResult( + '<ul type="circle" />', + '<ul style="list-style-type:circle;" />' + ); + } + + function testUlConvertTypeCaseInsensitive() { + $this->assertResult( + '<ul type="CIRCLE" />', + '<ul style="list-style-type:circle;" />' + ); + } + + function testUlRemoveInvalidType() { + $this->assertResult( + '<ul type="a" />', + '<ul />' + ); + } + + function testOlConvertType1() { + $this->assertResult( + '<ol type="1" />', + '<ol style="list-style-type:decimal;" />' + ); + } + + function testOlConvertTypeLowerI() { + $this->assertResult( + '<ol type="i" />', + '<ol style="list-style-type:lower-roman;" />' + ); + } + + function testOlConvertTypeUpperI() { + $this->assertResult( + '<ol type="I" />', + '<ol style="list-style-type:upper-roman;" />' + ); + } + + function testOlConvertTypeLowerA() { + $this->assertResult( + '<ol type="a" />', + '<ol style="list-style-type:lower-alpha;" />' + ); + } + + function testOlConvertTypeUpperA() { + $this->assertResult( + '<ol type="A" />', + '<ol style="list-style-type:upper-alpha;" />' + ); + } + + function testOlRemoveInvalidType() { + $this->assertResult( + '<ol type="disc" />', + '<ol />' + ); + } + + function testLiConvertTypeCircle() { + $this->assertResult( + '<li type="circle" />', + '<li style="list-style-type:circle;" />' + ); + } + + function testLiConvertTypeA() { + $this->assertResult( + '<li type="A" />', + '<li style="list-style-type:upper-alpha;" />' + ); + } + + function testLiConvertTypeCaseSensitive() { + $this->assertResult( + '<li type="CIRCLE" />', + '<li />' + ); + } + + +} + +// vim: et sw=4 sts=4 |