diff --git a/library/HTMLPurifier/Strategy/FixNesting.php b/library/HTMLPurifier/Strategy/FixNesting.php index bed1818a..e6a779e5 100644 --- a/library/HTMLPurifier/Strategy/FixNesting.php +++ b/library/HTMLPurifier/Strategy/FixNesting.php @@ -42,13 +42,15 @@ class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy $definition = $config->getHTMLDefinition(); // insert implicit "parent" node, will be removed at end. - // ! we might want to move this to configuration // DEFINITION CALL $parent_name = $definition->info_parent; array_unshift($tokens, new HTMLPurifier_Token_Start($parent_name)); $tokens[] = new HTMLPurifier_Token_End($parent_name); - // setup the context variables + // setup the context variable 'IsInline', for chameleon processing + // is 'false' when we are not inline, 'true' when it must always + // be inline, and an integer when it is inline for a certain + // branch of the document tree $is_inline = $definition->info_parent_def->descendants_are_inline; $context->register('IsInline', $is_inline); @@ -60,8 +62,9 @@ class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy $stack = array(); // stack that contains all elements that are excluded - // same structure as $stack, but it is only populated when an element - // with exclusions is processed, i.e. there won't be empty exclusions. + // it is organized by parent elements, similar to $stack, + // but it is only populated when an element with exclusions is + // processed, i.e. there won't be empty exclusions. $exclude_stack = array(); //####################################################################// @@ -110,7 +113,10 @@ class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy $parent_def = $definition->info[$parent_name]; } } else { - // unknown info, it won't be used anyway + // processing as if the parent were the "root" node + // unknown info, it won't be used anyway, in the future, + // we may want to enforce one element only (this is + // necessary for HTML Purifier to clean entire documents $parent_index = $parent_name = $parent_def = null; } @@ -207,6 +213,12 @@ class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy // current node is now the next possible start node // unless it turns out that we need to do a double-check + // this is a rought heuristic that covers 100% of HTML's + // cases and 99% of all other cases. A child definition + // that would be tricked by this would be something like: + // ( | a b c) where it's all or nothing. Fortunantely, + // our current implementation claims that that case would + // not allow empty, even if it did if (!$parent_def->child->allow_empty) { // we need to do a double-check $i = $parent_index; diff --git a/library/HTMLPurifier/Strategy/MakeWellFormed.php b/library/HTMLPurifier/Strategy/MakeWellFormed.php index 84580d3d..9d440452 100644 --- a/library/HTMLPurifier/Strategy/MakeWellFormed.php +++ b/library/HTMLPurifier/Strategy/MakeWellFormed.php @@ -62,6 +62,8 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy $parent_name = $parent->name; $parent_info = $definition->info[$parent_name]; + // we need to replace this with a more general + // algorithm if (isset($parent_info->auto_close[$token->name])) { $result[] = new HTMLPurifier_Token_End($parent_name); $result[] = $token; diff --git a/tests/HTMLPurifier/Strategy/FixNestingTest.php b/tests/HTMLPurifier/Strategy/FixNestingTest.php index 4c8a04a9..e68583a0 100644 --- a/tests/HTMLPurifier/Strategy/FixNestingTest.php +++ b/tests/HTMLPurifier/Strategy/FixNestingTest.php @@ -11,15 +11,12 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness $this->obj = new HTMLPurifier_Strategy_FixNesting(); } - function test() { - - $this->config = array('HTML.Doctype' => 'XHTML 1.0 Strict'); + function testBlockAndInlineIntegration() { // legal inline $this->assertResult('Bold text'); - // legal inline and block - // as the parent element is considered FLOW + // legal inline and block (default parent element is FLOW) $this->assertResult('Blank
Block
'); // illegal block in inline @@ -35,6 +32,10 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness array('Core.EscapeInvalidChildren' => true) ); + } + + function testNodeRemovalIntegration() { + // test of empty set that's required, resulting in removal of node $this->assertResult('', ''); @@ -44,27 +45,17 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness '' ); + } + + function testTableIntegration() { // test custom table definition $this->assertResult( - '
Cell 1
', '
Cell 1
' ); $this->assertResult('
', ''); - - // breaks without the redundant checking code - $this->assertResult('
', ''); - - // special case, prevents scrolling one back to find parent - $this->assertResult('
', ''); - - // cascading rollbacks - $this->assertResult( - '
', - '' - ); - - // rollbacks twice - $this->assertResult('
', ''); + } + + function testChameleonIntegration() { // block in inline ins not allowed $this->assertResult( @@ -84,12 +75,6 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness '

Not allowed!

' ); - // test exclusions - $this->assertResult( - 'Not allowed', - '' - ); - // stacked ins/del $this->assertResult( '

Not allowed!

', @@ -99,6 +84,17 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness '
Allowed!
' ); + } + + function testExclusionsIntegration() { + // test exclusions + $this->assertResult( + 'Not allowed', + '' + ); + } + + function testCustomParentIntegration() { // test inline parent $this->assertResult( 'Bold', true, array('HTML.Parent' => 'span') @@ -107,13 +103,31 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness '
Reject
', 'Reject', array('HTML.Parent' => 'span') ); + // test fallback to div $this->expectError('Cannot use unrecognized element as parent.'); $this->assertResult( - '
Accept
', true, array('HTML.Parent' => 'fling') + '
Accept
', true, array('HTML.Parent' => 'obviously-impossible') ); } + function testDoubleCheckIntegration() { + // breaks without the redundant checking code + $this->assertResult('
', ''); + + // special case, prevents scrolling one back to find parent + $this->assertResult('
', ''); + + // cascading rollbacks + $this->assertResult( + '
', + '' + ); + + // rollbacks twice + $this->assertResult('
', ''); + } + } ?> \ No newline at end of file diff --git a/tests/HTMLPurifier/Strategy/MakeWellFormedTest.php b/tests/HTMLPurifier/Strategy/MakeWellFormedTest.php index e1760a64..3aa7e302 100644 --- a/tests/HTMLPurifier/Strategy/MakeWellFormedTest.php +++ b/tests/HTMLPurifier/Strategy/MakeWellFormedTest.php @@ -11,13 +11,12 @@ class HTMLPurifier_Strategy_MakeWellFormedTest extends HTMLPurifier_StrategyHarn $this->obj = new HTMLPurifier_Strategy_MakeWellFormed(); } - function test() { - - $this->config = array('HTML.Doctype' => 'XHTML 1.0 Strict'); - + function testNormalIntegration() { $this->assertResult(''); $this->assertResult('This is bold text.'); - + } + + function testUnclosedTagIntegration() { $this->assertResult( 'Unclosed tag, gasp!', 'Unclosed tag, gasp!' @@ -32,7 +31,9 @@ class HTMLPurifier_Strategy_MakeWellFormedTest extends HTMLPurifier_StrategyHarn 'Unused end tags... recycle!', 'Unused end tags... recycle!' ); - + } + + function testEmptyTagDetectionIntegration() { $this->assertResult( '
', '
' @@ -42,8 +43,10 @@ class HTMLPurifier_Strategy_MakeWellFormedTest extends HTMLPurifier_StrategyHarn '
', '
' ); - - // test automatic paragraph closing + } + + function testAutoClose() { + // paragraph $this->assertResult( '

Paragraph 1

Paragraph 2', @@ -55,12 +58,20 @@ class HTMLPurifier_Strategy_MakeWellFormedTest extends HTMLPurifier_StrategyHarn '

Paragraphs

In

A

Div

' ); - // automatic list closing + // list $this->assertResult( '
  1. Item 1
  2. Item 2
', '
  1. Item 1
  2. Item 2
' ); + + // colgroup + + $this->assertResult( + '
', + '
' + ); + } } diff --git a/tests/HTMLPurifier/Test.php b/tests/HTMLPurifier/Test.php index 9fa61398..169d23ac 100644 --- a/tests/HTMLPurifier/Test.php +++ b/tests/HTMLPurifier/Test.php @@ -97,16 +97,6 @@ class HTMLPurifier_Test extends UnitTestCase } - function test_table() { - - $this->purifier = new HTMLPurifier(); - $this->assertPurification( -'
123
', -'
123
' - ); - - } - } ?> \ No newline at end of file