1
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-08-05 13:47:24 +02:00

Improve auto-paragraph to preserve newlines and handle edge-cases better.

This is a very large commit that includes numerous improvements to the
AutoParagraph injector.  These are:

* Rewritten flow control of the injector to use almost exclusively
  binary conditionals.
* Improved inline documentation with "State" comments, which give concise
  examples of what the token stack looks like at flow points.
* Documentation for all flow branches, even those with no actions.
* Factoring out of common operations to improve readability, especially the
  new iterator private methods.
* Expanded test-suite which covers new flow points, and corrects some errors
  in previous cases.

Signed-off-by: Edward Z. Yang <edwardzyang@thewritingpot.com>
This commit is contained in:
Edward Z. Yang
2008-08-10 00:32:29 -04:00
parent 0423985b45
commit 617f70a8ac
6 changed files with 515 additions and 207 deletions

View File

@@ -35,16 +35,6 @@ class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
*/
protected $lexer;
/**
* Default config to fall back on if no config is available
*/
protected $config;
/**
* Default context to fall back on if no context is available
*/
protected $context;
public function __construct() {
$this->lexer = new HTMLPurifier_Lexer_DirectLex();
parent::__construct();
@@ -88,7 +78,6 @@ class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
$expect = $this->generate($expect);
}
}
$this->assertIdentical($expect, $result);
}

View File

@@ -29,7 +29,9 @@ Par 1 still</p>'
'Par1
Par2',
'<p>Par1</p><p>Par2</p>'
"<p>Par1</p>
<p>Par2</p>"
);
}
@@ -40,7 +42,9 @@ Par2',
Par2',
'<p>Par1</p><p>Par2</p>'
'<p>Par1</p>
<p>Par2</p>'
);
}
@@ -49,7 +53,9 @@ Par2',
'<b>Par1</b>
<i>Par2</i>',
'<p><b>Par1</b></p><p><i>Par2</i></p>'
'<p><b>Par1</b></p>
<p><i>Par2</i></p>'
);
}
@@ -67,7 +73,9 @@ Par2</b></p>'
function testAddParagraphAdjacentToParagraph() {
$this->assertResult(
'Par1<p>Par2</p>',
'<p>Par1</p><p>Par2</p>'
'<p>Par1</p>
<p>Par2</p>'
);
}
@@ -91,7 +99,9 @@ Par1</pre>'
'Par1
',
'<p>Par1</p>'
'<p>Par1</p>
'
);
}
@@ -102,7 +112,11 @@ Par1</pre>'
<div>Par2</div>
Par3',
'<p>Par1</p><div>Par2</div><p>Par3</p>'
'<p>Par1</p>
<div>Par2</div>
<p>Par3</p>'
);
}
@@ -113,23 +127,29 @@ Par3',
);
}
function testIgnoreLeadingWhitespace() {
function testPreserveLeadingWhitespace() {
$this->assertResult(
'
Par',
'<p>Par</p>'
'
<p>Par</p>'
);
}
function testIgnoreSurroundingWhitespace() {
function testPreserveSurroundingWhitespace() {
$this->assertResult(
'
Par
',
'<p>Par</p>'
'
<p>Par</p>
'
);
}
@@ -138,7 +158,9 @@ Par
'<div>Par1
Par2</div>',
'<div><p>Par1</p><p>Par2</p></div>'
'<div><p>Par1</p>
<p>Par2</p></div>'
);
}
@@ -147,7 +169,9 @@ Par2</div>',
'<div><b>Par1</b>
Par2</div>',
'<div><p><b>Par1</b></p><p>Par2</p></div>'
'<div><p><b>Par1</b></p>
<p>Par2</p></div>'
);
}
@@ -160,7 +184,9 @@ Par2</div>',
'<div><b>Par1</b>
<i>Par2</i></div>',
'<div><p><b>Par1</b></p><p><i>Par2</i></p></div>'
'<div><p><b>Par1</b></p>
<p><i>Par2</i></p></div>'
);
}
@@ -177,7 +203,9 @@ Par2</div>',
'<div><p>Foo
Bar</p></div>',
'<div><p>Foo</p><p>Bar</p></div>'
'<div><p>Foo</p>
<p>Bar</p></div>'
);
}
@@ -186,7 +214,9 @@ Bar</p></div>',
'<div><p><b>Foo</b>
<i>Bar</i></p></div>',
'<div><p><b>Foo</b></p><p><i>Bar</i></p></div>'
'<div><p><b>Foo</b></p>
<p><i>Bar</i></p></div>'
);
}
@@ -199,7 +229,9 @@ Bar</p></div>',
'<blockquote>Par1
Par2</blockquote>',
'<blockquote><p>Par1</p><p>Par2</p></blockquote>'
'<blockquote><p>Par1</p>
<p>Par2</p></blockquote>'
);
}
@@ -218,7 +250,11 @@ Par2</blockquote>',
Bar
</div>',
'<div><p>Bar</p></div>'
'<div>
<p>Bar</p>
</div>'
);
}
@@ -229,7 +265,9 @@ Bar
Par2',
'<p><b>Par1</b>a</p><p>Par2</p>'
'<p><b>Par1</b>a</p>
<p>Par2</p>'
);
}
@@ -238,7 +276,9 @@ Par2',
'Par1
Par2</p>',
'<p>Par1</p><p>Par2</p>'
'<p>Par1</p>
<p>Par2</p>'
);
}
@@ -247,7 +287,9 @@ Par2</p>',
'Par1
Par2</div>',
'<p>Par1</p><p>Par2</p>'
'<p>Par1</p>
<p>Par2</p>'
);
}
@@ -264,7 +306,9 @@ Par1
'<div>Par1
<div>Par2</div></div>',
'<div><p>Par1</p><div>Par2</div></div>'
'<div><p>Par1</p>
<div>Par2</div></div>'
);
}
@@ -280,7 +324,9 @@ Par1
'Par1
<div>Par2</div>',
'<p>Par1
</p><div>Par2</div>'
</p>
<div>Par2</div>'
);
}
@@ -289,7 +335,9 @@ Par1
'Par1
<b>Par2</b>',
'<p>Par1</p><p><b>Par2</b></p>'
'<p>Par1</p>
<p><b>Par2</b></p>'
);
}
@@ -323,7 +371,9 @@ Par1
'<div><div>asdf</div>
<b>asdf</b></div>',
'<div><div>asdf</div><p><b>asdf</b></p></div>'
'<div><div>asdf</div>
<p><b>asdf</b></p></div>'
);
}
@@ -354,7 +404,9 @@ Par2'
'<div><code>bar</code> mmm
<pre>asdf</pre></div>',
'<div><p><code>bar</code> mmm</p><pre>asdf</pre></div>'
'<div><p><code>bar</code> mmm</p>
<pre>asdf</pre></div>'
);
}
@@ -363,7 +415,85 @@ Par2'
'<div>asdf <code>bar</code> mmm
<pre>asdf</pre></div>',
'<div><p>asdf <code>bar</code> mmm</p><pre>asdf</pre></div>'
'<div><p>asdf <code>bar</code> mmm</p>
<pre>asdf</pre></div>'
);
}
function testUpcomingTokenHasNewline() {
$this->assertResult(
'<div>Test<b>foo</b>bar<b>bing</b>bang
boo</div>',
'<div><p>Test<b>foo</b>bar<b>bing</b>bang</p>
<p>boo</p></div>'
);
}
function testEmptyTokenAtEndOfDiv() {
$this->assertResult(
'<div><p>foo</p>
</div>',
'<div><p>foo</p>
</div>'
);
}
function testEmptyDoubleLineTokenAtEndOfDiv() {
$this->assertResult(
'<div><p>foo</p>
</div>',
'<div><p>foo</p>
</div>'
);
}
function testTextState11Root() {
$this->assertResult('<div></div> ');
}
function testTextState11Element() {
$this->assertResult(
"<div><div></div>
</div>");
}
function testTextStateLikeElementState111NoWhitespace() {
$this->assertResult('<div><p>P</p>Boo</div>', '<div><p>P</p>Boo</div>');
}
function testElementState111NoWhitespace() {
$this->assertResult('<div><p>P</p><b>Boo</b></div>', '<div><p>P</p><b>Boo</b></div>');
}
function testElementState133() {
$this->assertResult(
"<div><b>B</b><pre>Ba</pre>
Bar</div>",
"<div><b>B</b><pre>Ba</pre>
<p>Bar</p></div>"
);
}
function testElementState22() {
$this->assertResult(
'<ul><li>foo</li></ul>'
);
}
function testElementState311() {
$this->assertResult(
'<p>Foo</p><b>Bar</b>',
'<p>Foo</p>
<p><b>Bar</b></p>'
);
}

View File

@@ -72,14 +72,18 @@ class HTMLPurifier_Strategy_MakeWellFormed_InjectorTest extends HTMLPurifier_Str
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>'
'<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>'
'<p><a href="http://example.com">http://example.com</a> </p>
<div><a href="http://example.com">http://example.com</a></div>'
);
}
@@ -92,24 +96,50 @@ class HTMLPurifier_Strategy_MakeWellFormed_InjectorTest extends HTMLPurifier_Str
function testParagraphAfterLinkifiedURL() {
$this->assertResult(
"http://google.com\n\n<b>b</b>",
"<p><a href=\"http://google.com\">http://google.com</a></p><p><b>b</b></p>"
"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\n\nasdf<b></b></p>\n\n<p></p><i></i>",
"<p>asdf</p><p>asdf</p>"
"<p>asdf
asdf<b></b></p>
<p></p><i></i>",
"<p>asdf</p>
<p>asdf</p>
"
);
}
function testRewindAndParagraph() {
// perhaps change the behavior of this?
$this->assertResult(
"bar\n\n<p><i></i>\n\n</p>\n\nfoo",
"<p>bar</p><p>foo</p>"
"bar
<p><i></i>
</p>
foo",
"<p>bar</p>
<p></p>
<p>foo</p>"
);
}