mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-08-05 05:37:49 +02:00
[2.0.1] Revamp error collector scheme: we now have custom mocks and an exchange of responsibilities
- Fix oversight in AutoParagraph dealing with armor. - Order errors with no line number last - Language object now needs $config and $context objects to do parameterized objects - Auto-close notice added - Token constructors accept line numbers git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1245 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
47
tests/HTMLPurifier/ErrorCollectorEMock.php
Normal file
47
tests/HTMLPurifier/ErrorCollectorEMock.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ErrorCollector.php';
|
||||
|
||||
generate_mock_once('HTMLPurifier_ErrorCollector');
|
||||
|
||||
/**
|
||||
* Extended error collector mock that has the ability to expect context
|
||||
*/
|
||||
class HTMLPurifier_ErrorCollectorEMock extends HTMLPurifier_ErrorCollectorMock
|
||||
{
|
||||
|
||||
var $_context;
|
||||
var $_expected_context = array();
|
||||
var $_expected_context_at = array();
|
||||
|
||||
function prepare(&$context) {
|
||||
$this->_context =& $context;
|
||||
}
|
||||
|
||||
function expectContext($key, $value) {
|
||||
$this->_expected_context[$key] = $value;
|
||||
}
|
||||
function expectContextAt($step, $key, $value) {
|
||||
$this->_expected_context_at[$step][$key] = $value;
|
||||
}
|
||||
|
||||
function send() {
|
||||
// test for context
|
||||
$test = &$this->_getCurrentTestCase();
|
||||
foreach ($this->_expected_context as $key => $value) {
|
||||
$test->assertEqual($value, $this->_context->get($key));
|
||||
}
|
||||
$step = $this->getCallCount('send');
|
||||
if (isset($this->_expected_context_at[$step])) {
|
||||
foreach ($this->_expected_context_at[$step] as $key => $value) {
|
||||
$test->assertEqual($value, $this->_context->get($key));
|
||||
}
|
||||
}
|
||||
// boilerplate mock code, does not have return value or references
|
||||
$args = func_get_args();
|
||||
$this->_invoke('send', $args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@@ -26,7 +26,7 @@ class HTMLPurifier_ErrorCollectorTest extends UnitTestCase
|
||||
$context->register('Locale', $language);
|
||||
$context->register('CurrentLine', $line);
|
||||
|
||||
$generator = new HTMLPurifier_GeneratorMock();
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
$context->register('Generator', $generator);
|
||||
|
||||
$collector = new HTMLPurifier_ErrorCollector($context);
|
||||
@@ -60,7 +60,7 @@ class HTMLPurifier_ErrorCollectorTest extends UnitTestCase
|
||||
$context = new HTMLPurifier_Context();
|
||||
$context->register('Locale', $language);
|
||||
|
||||
$generator = new HTMLPurifier_GeneratorMock();
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
$context->register('Generator', $generator);
|
||||
|
||||
$collector = new HTMLPurifier_ErrorCollector($context);
|
||||
@@ -77,7 +77,7 @@ class HTMLPurifier_ErrorCollectorTest extends UnitTestCase
|
||||
$context = new HTMLPurifier_Context();
|
||||
$context->register('Locale', $language);
|
||||
|
||||
$generator = new HTMLPurifier_GeneratorMock();
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
$context->register('Generator', $generator);
|
||||
|
||||
$collector = new HTMLPurifier_ErrorCollector($context);
|
||||
@@ -100,32 +100,36 @@ class HTMLPurifier_ErrorCollectorTest extends UnitTestCase
|
||||
function testContextSubstitutions() {
|
||||
|
||||
$language = new HTMLPurifier_LanguageMock();
|
||||
$language->setReturnValue('getMessage',
|
||||
'$CurrentToken.Name, $CurrentToken.Serialized', array('message-token'));
|
||||
$language->setReturnValue('getMessage',
|
||||
'$CurrentAttr.Name => $CurrentAttr.Value', array('message-attr'));
|
||||
$context = new HTMLPurifier_Context();
|
||||
$context = new HTMLPurifier_Context();
|
||||
$context->register('Locale', $language);
|
||||
|
||||
$current_token = new HTMLPurifier_Token_Start('a', array('href' => 'http://example.com'));
|
||||
$current_token->line = 32;
|
||||
$current_attr = 'href';
|
||||
|
||||
$generator = new HTMLPurifier_GeneratorMock();
|
||||
$generator->setReturnValue('generateFromToken', '<a href="http://example.com">', array($current_token));
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
$context->register('Generator', $generator);
|
||||
|
||||
$current_token = false;
|
||||
$context->register('CurrentToken', $current_token);
|
||||
|
||||
$collector = new HTMLPurifier_ErrorCollector($context);
|
||||
|
||||
$context->register('CurrentToken', $current_token);
|
||||
$collector->send(E_NOTICE, 'message-token');
|
||||
// 0
|
||||
$current_token = new HTMLPurifier_Token_Start('a', array('href' => 'http://example.com'), 32);
|
||||
$language->setReturnValue('formatMessage', 'Token message',
|
||||
array('message-data-token', array('CurrentToken' => $current_token)));
|
||||
$collector->send(E_NOTICE, 'message-data-token');
|
||||
|
||||
$current_attr = 'href';
|
||||
$language->setReturnValue('formatMessage', '$CurrentAttr.Name => $CurrentAttr.Value',
|
||||
array('message-attr', array('CurrentToken' => $current_token)));
|
||||
|
||||
// 1
|
||||
$collector->send(E_NOTICE, 'message-attr'); // test when context isn't available
|
||||
|
||||
// 2
|
||||
$context->register('CurrentAttr', $current_attr);
|
||||
$collector->send(E_NOTICE, 'message-attr');
|
||||
|
||||
$result = array(
|
||||
0 => array(32, E_NOTICE, 'a, <a href="http://example.com">'),
|
||||
0 => array(32, E_NOTICE, 'Token message'),
|
||||
1 => array(32, E_NOTICE, '$CurrentAttr.Name => $CurrentAttr.Value'),
|
||||
2 => array(32, E_NOTICE, 'href => http://example.com')
|
||||
);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ErrorCollector.php';
|
||||
require_once 'HTMLPurifier/ErrorCollectorEMock.php';
|
||||
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
||||
|
||||
class HTMLPurifier_ErrorsHarness extends UnitTestCase
|
||||
@@ -13,7 +13,8 @@ class HTMLPurifier_ErrorsHarness extends UnitTestCase
|
||||
$this->config = HTMLPurifier_Config::create(array('Core.CollectErrors' => true));
|
||||
$this->context = new HTMLPurifier_Context();
|
||||
generate_mock_once('HTMLPurifier_ErrorCollector');
|
||||
$this->collector = new HTMLPurifier_ErrorCollectorMock();
|
||||
$this->collector = new HTMLPurifier_ErrorCollectorEMock();
|
||||
$this->collector->prepare($this->context);
|
||||
$this->context->register('ErrorCollector', $this->collector);
|
||||
}
|
||||
|
||||
@@ -22,6 +23,10 @@ class HTMLPurifier_ErrorsHarness extends UnitTestCase
|
||||
$this->collector->expectOnce('send', $args);
|
||||
}
|
||||
|
||||
function expectContext($key, $value) {
|
||||
$this->collector->expectContext($key, $value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@@ -9,7 +9,9 @@ class HTMLPurifier_LanguageFactoryTest extends UnitTestCase
|
||||
|
||||
$factory = HTMLPurifier_LanguageFactory::instance();
|
||||
|
||||
$language = $factory->create('en');
|
||||
$config = HTMLPurifier_Config::create(array('Core.Language' => 'en'));
|
||||
$context = new HTMLPurifier_Context();
|
||||
$language = $factory->create($config, $context);
|
||||
|
||||
$this->assertIsA($language, 'HTMLPurifier_Language');
|
||||
$this->assertIdentical($language->code, 'en');
|
||||
@@ -27,7 +29,10 @@ class HTMLPurifier_LanguageFactoryTest extends UnitTestCase
|
||||
|
||||
$factory = HTMLPurifier_LanguageFactory::instance();
|
||||
|
||||
$language = $factory->create('en-x-test');
|
||||
$config = HTMLPurifier_Config::create(array('Core.Language' => 'en-x-test'));
|
||||
$context = new HTMLPurifier_Context();
|
||||
|
||||
$language = $factory->create($config, $context);
|
||||
|
||||
$this->assertIsA($language, 'HTMLPurifier_Language_en_x_test');
|
||||
$this->assertIdentical($language->code, 'en-x-test');
|
||||
|
@@ -8,7 +8,9 @@ class HTMLPurifier_LanguageTest extends UnitTestCase
|
||||
var $lang;
|
||||
|
||||
function test_getMessage() {
|
||||
$lang = new HTMLPurifier_Language();
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$context = new HTMLPurifier_Context();
|
||||
$lang = new HTMLPurifier_Language($config, $context);
|
||||
$lang->_loaded = true;
|
||||
$lang->messages['HTMLPurifier'] = 'HTML Purifier';
|
||||
$this->assertIdentical($lang->getMessage('HTMLPurifier'), 'HTML Purifier');
|
||||
@@ -16,12 +18,31 @@ class HTMLPurifier_LanguageTest extends UnitTestCase
|
||||
}
|
||||
|
||||
function test_formatMessage() {
|
||||
$lang = new HTMLPurifier_Language();
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$context = new HTMLPurifier_Context();
|
||||
$lang = new HTMLPurifier_Language($config, $context);
|
||||
$lang->_loaded = true;
|
||||
$lang->messages['LanguageTest: Error'] = 'Error is $1 on line $2';
|
||||
$this->assertIdentical($lang->formatMessage('LanguageTest: Error', array(1=>'fatal', 32)), 'Error is fatal on line 32');
|
||||
}
|
||||
|
||||
function test_formatMessage_complexParameter() {
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$context = new HTMLPurifier_Context();
|
||||
$generator = new HTMLPurifier_Generator(); // replace with mock if this gets icky
|
||||
$context->register('Generator', $generator);
|
||||
$lang = new HTMLPurifier_Language($config, $context);
|
||||
$lang->_loaded = true;
|
||||
$lang->messages['LanguageTest: Element info'] = 'Element Token: $1.Name, $1.Serialized, $1.Compact, $1.Line';
|
||||
$lang->messages['LanguageTest: Data info'] = 'Data Token: $1.Data, $1.Serialized, $1.Compact, $1.Line';
|
||||
$this->assertIdentical($lang->formatMessage('LanguageTest: Element info',
|
||||
array(1=>new HTMLPurifier_Token_Start('a', array('href'=>'http://example.com'), 18))),
|
||||
'Element Token: a, <a href="http://example.com">, <a>, 18');
|
||||
$this->assertIdentical($lang->formatMessage('LanguageTest: Data info',
|
||||
array(1=>new HTMLPurifier_Token_Text('data>', 23))),
|
||||
'Data Token: data>, data>, data>, 23');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@@ -18,19 +18,24 @@ class HTMLPurifier_Lexer_DirectLex_ErrorsTest extends HTMLPurifier_ErrorsHarness
|
||||
|
||||
function testUnclosedComment() {
|
||||
$this->expectErrorCollection(E_WARNING, 'Lexer: Unclosed comment');
|
||||
$this->expectContext('CurrentLine', 1);
|
||||
$this->invoke('<!-- >');
|
||||
}
|
||||
|
||||
function testUnescapedLt() {
|
||||
$this->expectErrorCollection(E_NOTICE, 'Lexer: Unescaped lt');
|
||||
$this->expectContext('CurrentLine', 1);
|
||||
$this->invoke('< foo>');
|
||||
}
|
||||
|
||||
function testMissingGt() {
|
||||
$this->expectErrorCollection(E_WARNING, 'Lexer: Missing gt');
|
||||
$this->expectContext('CurrentLine', 1);
|
||||
$this->invoke('<a href=""');
|
||||
}
|
||||
|
||||
// these are sub-errors, will only be thrown in context of collector
|
||||
|
||||
function testMissingAttributeKey1() {
|
||||
$this->expectErrorCollection(E_ERROR, 'Lexer: Missing attribute key');
|
||||
$this->invokeAttr('=""');
|
||||
|
@@ -16,34 +16,44 @@ class HTMLPurifier_Strategy_MakeWellFormed_ErrorsTest extends HTMLPurifier_Strat
|
||||
}
|
||||
|
||||
function testUnnecessaryEndTagRemoved() {
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed', 'b');
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed');
|
||||
$this->expectContext('CurrentToken', new HTMLPurifier_Token_End('b', array(), 1));
|
||||
$this->invoke('</b>');
|
||||
}
|
||||
|
||||
function testUnnecessaryEndTagToText() {
|
||||
$this->config->set('Core', 'EscapeInvalidTags', true);
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text', 'b');
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text');
|
||||
$this->expectContext('CurrentToken', new HTMLPurifier_Token_End('b', array(), 1));
|
||||
$this->invoke('</b>');
|
||||
}
|
||||
|
||||
function testTagAutoClosed() {
|
||||
$this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', new HTMLPurifier_Token_Start('b', array(), 1));
|
||||
$this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('div', array(), 1));
|
||||
$this->invoke('<b>Foo<div>Bar</div>');
|
||||
}
|
||||
|
||||
function testStrayEndTagRemoved() {
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed', 'b');
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed');
|
||||
$this->expectContext('CurrentToken', new HTMLPurifier_Token_End('b', array(), 1));
|
||||
$this->invoke('<i></b></i>');
|
||||
}
|
||||
|
||||
function testStrayEndTagToText() {
|
||||
$this->config->set('Core', 'EscapeInvalidTags', true);
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text', 'b');
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text');
|
||||
$this->expectContext('CurrentToken', new HTMLPurifier_Token_End('b', array(), 1));
|
||||
$this->invoke('<i></b></i>');
|
||||
}
|
||||
|
||||
function testTagClosedByElementEnd() {
|
||||
$this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', 'b');
|
||||
$this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', new HTMLPurifier_Token_Start('b', array(), 1));
|
||||
$this->invoke('<i><b>Foobar</i>');
|
||||
}
|
||||
|
||||
function testTagClosedByDocumentEnd() {
|
||||
$this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', 'b');
|
||||
$this->expectErrorCollection(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', new HTMLPurifier_Token_Start('b', array(), 1));
|
||||
$this->invoke('<b>Foobar');
|
||||
}
|
||||
|
||||
|
@@ -16,37 +16,41 @@ class HTMLPurifier_Strategy_RemoveForeignElements_ErrorsTest extends HTMLPurifie
|
||||
}
|
||||
|
||||
function testTagTransform() {
|
||||
// uses $CurrentToken.Serialized
|
||||
$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', 'img', 'alt');
|
||||
$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() {
|
||||
// uses $CurrentToken.Serialized
|
||||
$this->config->set('Core', 'EscapeInvalidTags', true);
|
||||
$this->expectErrorCollection(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text');
|
||||
$this->invoke('<cannot-possibly-exist-element>');
|
||||
$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->invoke('<cannot-possibly-exist-element>');
|
||||
$this->expectContext('CurrentToken', new HTMLPurifier_Token_Start('invalid', array(), 1));
|
||||
$this->invoke('<invalid>');
|
||||
}
|
||||
|
||||
function testCommentRemoved() {
|
||||
$this->expectErrorCollection(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed', ' test ');
|
||||
$this->expectErrorCollection(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed');
|
||||
$this->expectContext('CurrentToken', new HTMLPurifier_Token_Comment(' test ', 1));
|
||||
$this->invoke('<!-- test -->');
|
||||
}
|
||||
|
||||
function testScriptRemoved() {
|
||||
$this->collector->expectAt(0, 'send', array(E_ERROR, 'Strategy_RemoveForeignElements: Script 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');
|
||||
}
|
||||
|
Reference in New Issue
Block a user