mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-01-03 13:21:51 +00:00
[1.7.0] Various updates
- Implement addModule(), requires new userModules property - Remove unnecessary $config passing for getElement(s) - Revamp HTMLModuleManagerTest - Fix buggy unit test for unrecognized parent - Remove anonymous generator member variable from ChildDef_Required git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1063 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
parent
2cbb3be602
commit
831a09d455
@ -29,7 +29,6 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
|
||||
}
|
||||
}
|
||||
$this->elements = $elements;
|
||||
$this->gen = new HTMLPurifier_Generator();
|
||||
}
|
||||
var $allow_empty = false;
|
||||
var $type = 'required';
|
||||
@ -57,6 +56,12 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
|
||||
// some configuration
|
||||
$escape_invalid_children = $config->get('Core', 'EscapeInvalidChildren');
|
||||
|
||||
// generator
|
||||
static $gen = null;
|
||||
if ($gen === null) {
|
||||
$gen = new HTMLPurifier_Generator();
|
||||
}
|
||||
|
||||
foreach ($tokens_of_children as $token) {
|
||||
if (!empty($token->is_whitespace)) {
|
||||
$result[] = $token;
|
||||
@ -80,7 +85,7 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
|
||||
$result[] = $token;
|
||||
} elseif ($pcdata_allowed && $escape_invalid_children) {
|
||||
$result[] = new HTMLPurifier_Token_Text(
|
||||
$this->gen->generateFromToken($token, $config)
|
||||
$gen->generateFromToken($token, $config)
|
||||
);
|
||||
}
|
||||
continue;
|
||||
@ -91,7 +96,7 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
|
||||
} elseif ($pcdata_allowed && $escape_invalid_children) {
|
||||
$result[] =
|
||||
new HTMLPurifier_Token_Text(
|
||||
$this->gen->generateFromToken( $token, $config )
|
||||
$gen->generateFromToken( $token, $config )
|
||||
);
|
||||
} else {
|
||||
// drop silently
|
||||
|
@ -198,7 +198,7 @@ class HTMLPurifier_HTMLDefinition
|
||||
}
|
||||
}
|
||||
|
||||
$this->info = $this->manager->getElements($this->config);
|
||||
$this->info = $this->manager->getElements();
|
||||
$this->info_content_sets = $this->manager->contentSets->lookup;
|
||||
|
||||
}
|
||||
@ -217,15 +217,14 @@ class HTMLPurifier_HTMLDefinition
|
||||
}
|
||||
|
||||
$parent = $this->config->get('HTML', 'Parent');
|
||||
$def = $this->manager->getElement($parent, $this->config);
|
||||
$def = $this->manager->getElement($parent, true);
|
||||
if ($def) {
|
||||
$this->info_parent = $parent;
|
||||
$this->info_parent_def = $def;
|
||||
} else {
|
||||
trigger_error('Cannot use unrecognized element as parent.',
|
||||
E_USER_ERROR);
|
||||
$this->info_parent_def = $this->manager->getElement(
|
||||
$this->info_parent, $this->config);
|
||||
$this->info_parent_def = $this->manager->getElement($this->info_parent, true);
|
||||
}
|
||||
|
||||
// support template text
|
||||
|
@ -136,7 +136,7 @@ class HTMLPurifier_HTMLModule
|
||||
* can set advanced parameters
|
||||
* @protected
|
||||
*/
|
||||
function &addElement($element, $safe, $type, $contents, $attr_includes, $attr = array()) {
|
||||
function &addElement($element, $safe, $type, $contents, $attr_includes = array(), $attr = array()) {
|
||||
$this->elements[] = $element;
|
||||
// parse content_model
|
||||
list($content_model_type, $content_model) = $this->parseContents($contents);
|
||||
|
@ -76,6 +76,13 @@ class HTMLPurifier_HTMLModuleManager
|
||||
*/
|
||||
var $registeredModules = array();
|
||||
|
||||
/**
|
||||
* List of extra modules that were added by the user using addModule().
|
||||
* These get unconditionally merged into the current doctype, whatever
|
||||
* it may be.
|
||||
*/
|
||||
var $userModules = array();
|
||||
|
||||
/**
|
||||
* Associative array of element name to list of modules that have
|
||||
* definitions for the element; this array is dynamically filled.
|
||||
@ -210,7 +217,9 @@ class HTMLPurifier_HTMLModuleManager
|
||||
* and then tacking it on to the active doctype
|
||||
*/
|
||||
function addModule($module) {
|
||||
// unimplemented
|
||||
$this->registerModule($module);
|
||||
if (is_object($module)) $module = $module->name;
|
||||
$this->userModules[] = $module;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,16 +243,19 @@ class HTMLPurifier_HTMLModuleManager
|
||||
$doctype = $this->doctypes->make($config);
|
||||
$modules = $doctype->modules;
|
||||
|
||||
// merge in custom modules
|
||||
$modules = array_merge($modules, $this->userModules);
|
||||
|
||||
foreach ($modules as $module) {
|
||||
if (is_object($module)) {
|
||||
$this->modules[$module->name] = $module;
|
||||
$this->registeredModules[$module->name] = $module;
|
||||
continue;
|
||||
} else {
|
||||
if (!isset($this->modules[$module])) {
|
||||
if (!isset($this->registeredModules[$module])) {
|
||||
$this->registerModule($module);
|
||||
}
|
||||
$this->modules[$module] = $this->registeredModules[$module];
|
||||
}
|
||||
$this->modules[$module] = $this->registeredModules[$module];
|
||||
}
|
||||
|
||||
// setup lookup table based on all valid modules
|
||||
@ -274,11 +286,9 @@ class HTMLPurifier_HTMLModuleManager
|
||||
|
||||
/**
|
||||
* Retrieves merged element definitions.
|
||||
* @param $config Instance of HTMLPurifier_Config, for determining
|
||||
* stray elements.
|
||||
* @return Array of HTMLPurifier_ElementDef
|
||||
*/
|
||||
function getElements($config) {
|
||||
function getElements() {
|
||||
|
||||
$elements = array();
|
||||
foreach ($this->modules as $module) {
|
||||
@ -286,7 +296,7 @@ class HTMLPurifier_HTMLModuleManager
|
||||
if (isset($elements[$name])) continue;
|
||||
// if element is not safe, don't use it
|
||||
if (!$this->trusted && ($v->safe === false)) continue;
|
||||
$elements[$name] = $this->getElement($name, $config);
|
||||
$elements[$name] = $this->getElement($name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,12 +313,11 @@ class HTMLPurifier_HTMLModuleManager
|
||||
/**
|
||||
* Retrieves a single merged element definition
|
||||
* @param $name Name of element
|
||||
* @param $config Instance of HTMLPurifier_Config, may not be necessary.
|
||||
* @param $trusted Boolean trusted overriding parameter: set to true
|
||||
* if you want the full version of an element
|
||||
* @return Merged HTMLPurifier_ElementDef
|
||||
*/
|
||||
function getElement($name, $config, $trusted = null) {
|
||||
function getElement($name, $trusted = null) {
|
||||
|
||||
$def = false;
|
||||
if ($trusted === null) $trusted = $this->trusted;
|
||||
|
@ -2,283 +2,76 @@
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModuleManager.php';
|
||||
|
||||
// stub classes for unit testing
|
||||
class HTMLPurifier_HTMLModule_ManagerTestModule extends HTMLPurifier_HTMLModule {
|
||||
var $name = 'ManagerTestModule';
|
||||
}
|
||||
class HTMLPurifier_HTMLModuleManagerTest_TestModule extends HTMLPurifier_HTMLModule {
|
||||
var $name = 'TestModule';
|
||||
}
|
||||
|
||||
class HTMLPurifier_HTMLModuleManagerTest extends UnitTestCase
|
||||
{
|
||||
|
||||
// unit tests temporarily disabled as we do big refactoring
|
||||
function test_addModule() {
|
||||
$manager = new HTMLPurifier_HTMLModuleManager();
|
||||
$manager->doctypes->register('Blank'); // doctype normally is blank...
|
||||
|
||||
/**
|
||||
* System under test, instance of HTMLPurifier_HTMLModuleManager.
|
||||
*/
|
||||
var $manager;
|
||||
generate_mock_once('HTMLPurifier_AttrDef');
|
||||
$attrdef_nmtokens =& new HTMLPurifier_AttrDefMock($this);
|
||||
$manager->attrTypes->info['NMTOKENS'] =& $attrdef_nmtokens;
|
||||
|
||||
function setup() {
|
||||
$this->manager = new HTMLPurifier_HTMLModuleManager(true);
|
||||
}
|
||||
// ...but we add user modules
|
||||
|
||||
function teardown() {
|
||||
tally_errors($this);
|
||||
}
|
||||
$common_module = new HTMLPurifier_HTMLModule();
|
||||
$common_module->name = 'Common';
|
||||
$common_module->attr_collections['Common'] = array('class' => 'NMTOKENS');
|
||||
$common_module->content_sets['Flow'] = 'Block | Inline';
|
||||
$manager->addModule($common_module);
|
||||
|
||||
function createModule($name) {
|
||||
$module = new HTMLPurifier_HTMLModule();
|
||||
$module->name = $name;
|
||||
return $module;
|
||||
}
|
||||
$structural_module = new HTMLPurifier_HTMLModule();
|
||||
$structural_module->name = 'Structural';
|
||||
$structural_module->addElement('p', true, 'Block', 'Inline', 'Common');
|
||||
$structural_module->addElement('div', false, 'Block', 'Flow');
|
||||
$manager->addModule($structural_module);
|
||||
|
||||
function untest_addModule_withAutoload() {
|
||||
$this->manager->autoDoctype = 'Generic Document 0.1';
|
||||
$this->manager->autoCollection = 'Default';
|
||||
$formatting_module = new HTMLPurifier_HTMLModule();
|
||||
$formatting_module->name = 'Formatting';
|
||||
$formatting_module->addElement('em', true, 'Inline', 'Inline', 'Common');
|
||||
$manager->addModule($formatting_module);
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule();
|
||||
$module->name = 'Module';
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML', 'Trusted', false);
|
||||
$config->set('HTML', 'Doctype', 'Blank');
|
||||
|
||||
$module2 = new HTMLPurifier_HTMLModule();
|
||||
$module2->name = 'Module2';
|
||||
$manager->setup($config);
|
||||
|
||||
// we need to grab the dynamically generated orders from
|
||||
// the object since modules are not passed by reference
|
||||
$p = new HTMLPurifier_ElementDef();
|
||||
$p->attr['class'] = $attrdef_nmtokens;
|
||||
$p->child = new HTMLPurifier_ChildDef_Optional(array('em', '#PCDATA'));
|
||||
$p->content_model = 'em | #PCDATA';
|
||||
$p->content_model_type = 'optional';
|
||||
$p->descendants_are_inline = true;
|
||||
$p->safe = true;
|
||||
|
||||
$this->manager->addModule($module);
|
||||
$module_order = $this->manager->modules['Module']->order;
|
||||
$module->order = $module_order;
|
||||
$this->assertIdentical($module, $this->manager->modules['Module']);
|
||||
$em = new HTMLPurifier_ElementDef();
|
||||
$em->attr['class'] = $attrdef_nmtokens;
|
||||
$em->child = new HTMLPurifier_ChildDef_Optional(array('em', '#PCDATA'));
|
||||
$em->content_model = 'em | #PCDATA';
|
||||
$em->content_model_type = 'optional';
|
||||
$em->descendants_are_inline = true;
|
||||
$em->safe = true;
|
||||
|
||||
$this->manager->addModule($module2);
|
||||
$module2_order = $this->manager->modules['Module2']->order;
|
||||
$module2->order = $module2_order;
|
||||
$this->assertIdentical($module2, $this->manager->modules['Module2']);
|
||||
$this->assertIdentical($module_order + 1, $module2_order);
|
||||
|
||||
$this->assertIdentical(
|
||||
$this->manager->collections['Default']['Generic Document 0.1'],
|
||||
array('Module', 'Module2')
|
||||
$this->assertEqual(
|
||||
array('p' => $p, 'em' => $em),
|
||||
$manager->getElements()
|
||||
);
|
||||
|
||||
$this->manager->setup(HTMLPurifier_Config::createDefault());
|
||||
// test trusted parameter override
|
||||
|
||||
$modules = array(
|
||||
'Module' => $this->manager->modules['Module'],
|
||||
'Module2' => $this->manager->modules['Module2']
|
||||
);
|
||||
$div = new HTMLPurifier_ElementDef();
|
||||
$div->child = new HTMLPurifier_ChildDef_Optional(array('p', 'div', 'em', '#PCDATA'));
|
||||
$div->content_model = 'p | div | em | #PCDATA';
|
||||
$div->content_model_type = 'optional';
|
||||
$div->descendants_are_inline = false;
|
||||
$div->safe = false;
|
||||
|
||||
$this->assertIdentical(
|
||||
$this->manager->collections['Default']['Generic Document 0.1'],
|
||||
$modules
|
||||
);
|
||||
$this->assertIdentical($this->manager->activeModules, $modules);
|
||||
$this->assertIdentical($this->manager->activeCollections, array('Default'));
|
||||
$this->assertEqual($div, $manager->getElement('div', true));
|
||||
|
||||
}
|
||||
|
||||
function untest_addModule_undefinedClass() {
|
||||
$this->expectError('TotallyCannotBeDefined module does not exist');
|
||||
$this->manager->addModule('TotallyCannotBeDefined');
|
||||
}
|
||||
|
||||
function untest_addModule_stringExpansion() {
|
||||
$this->manager->addModule('ManagerTestModule');
|
||||
$this->assertIsA($this->manager->modules['ManagerTestModule'],
|
||||
'HTMLPurifier_HTMLModule_ManagerTestModule');
|
||||
}
|
||||
|
||||
function untest_addPrefix() {
|
||||
$this->manager->addPrefix('HTMLPurifier_HTMLModuleManagerTest_');
|
||||
$this->manager->addModule('TestModule');
|
||||
$this->assertIsA($this->manager->modules['TestModule'],
|
||||
'HTMLPurifier_HTMLModuleManagerTest_TestModule');
|
||||
}
|
||||
|
||||
function assertProcessCollections($input, $expect = false) {
|
||||
if ($expect === false) $expect = $input;
|
||||
$this->manager->processCollections($input);
|
||||
// substitute in modules for $expect
|
||||
foreach ($expect as $col_i => $col) {
|
||||
$disable = false;
|
||||
foreach ($col as $mod_i => $mod) {
|
||||
unset($expect[$col_i][$mod_i]);
|
||||
if ($mod_i === '*') {
|
||||
$disable = true;
|
||||
continue;
|
||||
}
|
||||
$expect[$col_i][$mod] = $this->manager->modules[$mod];
|
||||
}
|
||||
if ($disable) $expect[$col_i]['*'] = false;
|
||||
}
|
||||
$this->assertIdentical($input, $expect);
|
||||
}
|
||||
|
||||
function untestImpl_processCollections() {
|
||||
$this->manager->initialize();
|
||||
$this->assertProcessCollections(
|
||||
array()
|
||||
);
|
||||
$this->assertProcessCollections(
|
||||
array('HTML' => array('Text'))
|
||||
);
|
||||
$this->assertProcessCollections(
|
||||
array('HTML' => array('Text', 'Legacy'))
|
||||
);
|
||||
$this->assertProcessCollections( // order is important!
|
||||
array('HTML' => array('Legacy', 'Text')),
|
||||
array('HTML' => array('Text', 'Legacy'))
|
||||
);
|
||||
$this->assertProcessCollections( // privates removed after process
|
||||
array('_Private' => array('Legacy', 'Text')),
|
||||
array()
|
||||
);
|
||||
$this->assertProcessCollections( // inclusions come first
|
||||
array(
|
||||
'HTML' => array(array('XHTML'), 'Legacy'),
|
||||
'XHTML' => array('Text', 'Hypertext')
|
||||
),
|
||||
array(
|
||||
'HTML' => array('Text', 'Hypertext', 'Legacy'),
|
||||
'XHTML' => array('Text', 'Hypertext')
|
||||
)
|
||||
);
|
||||
$this->assertProcessCollections(
|
||||
array(
|
||||
'HTML' => array(array('_Common'), 'Legacy'),
|
||||
'_Common' => array('Text', 'Hypertext')
|
||||
),
|
||||
array(
|
||||
'HTML' => array('Text', 'Hypertext', 'Legacy')
|
||||
)
|
||||
);
|
||||
$this->assertProcessCollections( // nested inclusions
|
||||
array(
|
||||
'Full' => array(array('Minimal'), 'Hypertext'),
|
||||
'Minimal' => array(array('Bare'), 'List'),
|
||||
'Bare' => array('Text')
|
||||
),
|
||||
array(
|
||||
'Full' => array('Text', 'Hypertext', 'List'),
|
||||
'Minimal' => array('Text', 'List'),
|
||||
'Bare' => array('Text')
|
||||
)
|
||||
);
|
||||
// strange but valid stuff that will be handled in assembleModules
|
||||
$this->assertProcessCollections(
|
||||
array(
|
||||
'Linky' => array('Hypertext'),
|
||||
'Listy' => array('List'),
|
||||
'*' => array('Text')
|
||||
)
|
||||
);
|
||||
$this->assertProcessCollections(
|
||||
array(
|
||||
'Linky' => array('Hypertext'),
|
||||
'ListyOnly' => array('List', '*' => false),
|
||||
'*' => array('Text')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function untestImpl_processCollections_error() {
|
||||
$this->manager->initialize();
|
||||
|
||||
$this->expectError( // active variables, watch out!
|
||||
'Illegal inclusion array at index 1 found collection HTML, '.
|
||||
'inclusion arrays must be at start of collection (index 0)');
|
||||
$c = array(
|
||||
'HTML' => array('Legacy', array('XHTML')),
|
||||
'XHTML' => array('Text', 'Hypertext')
|
||||
|
||||
|
||||
);
|
||||
$this->manager->processCollections($c);
|
||||
unset($c);
|
||||
|
||||
$this->expectError('Collection HTML references undefined '.
|
||||
'module Foobar');
|
||||
$c = array(
|
||||
'HTML' => array('Foobar')
|
||||
|
||||
|
||||
);
|
||||
$this->manager->processCollections($c);
|
||||
unset($c);
|
||||
|
||||
$this->expectError('Collection HTML tried to include undefined '.
|
||||
'collection _Common');
|
||||
$c = array(
|
||||
'HTML' => array(array('_Common'), 'Legacy')
|
||||
|
||||
|
||||
);
|
||||
$this->manager->processCollections($c);
|
||||
unset($c);
|
||||
|
||||
// reports the first circular inclusion it runs across
|
||||
$this->expectError('Circular inclusion detected in HTML collection');
|
||||
$c = array(
|
||||
'HTML' => array(array('XHTML')),
|
||||
'XHTML' => array(array('HTML'))
|
||||
|
||||
|
||||
);
|
||||
$this->manager->processCollections($c);
|
||||
unset($c);
|
||||
|
||||
}
|
||||
|
||||
function untest_makeCollection() {
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.Doctype' => 'Custom Doctype'
|
||||
));
|
||||
$this->manager->addModule($this->createModule('ActiveModule'));
|
||||
$this->manager->addModule($this->createModule('DudModule'));
|
||||
$this->manager->addModule($this->createModule('ValidModule'));
|
||||
$ActiveModule = $this->manager->modules['ActiveModule'];
|
||||
$DudModule = $this->manager->modules['DudModule'];
|
||||
$ValidModule = $this->manager->modules['ValidModule'];
|
||||
$this->manager->collections['ToBeValid']['Custom Doctype'] = array('ValidModule');
|
||||
$this->manager->collections['ToBeActive']['Custom Doctype'] = array('ActiveModule');
|
||||
$this->manager->makeCollectionValid('ToBeValid');
|
||||
$this->manager->makeCollectionActive('ToBeActive');
|
||||
$this->manager->setup($config);
|
||||
$this->assertIdentical($this->manager->validModules, array(
|
||||
'ValidModule' => $ValidModule,
|
||||
'ActiveModule' => $ActiveModule
|
||||
));
|
||||
$this->assertIdentical($this->manager->activeModules, array(
|
||||
'ActiveModule' => $ActiveModule
|
||||
));
|
||||
}
|
||||
|
||||
function untest_makeCollection_undefinedCollection() {
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.Doctype' => 'Sweets Document 1.0'
|
||||
));
|
||||
$this->manager->addModule($this->createModule('DonutsModule'));
|
||||
$this->manager->addModule($this->createModule('ChocolateModule'));
|
||||
$this->manager->collections['CocoaBased']['Sweets Document 1.0'] = array('ChocolateModule');
|
||||
// notice how BreadBased collection is missing
|
||||
$this->manager->makeCollectionActive('CocoaBased'); // to prevent other errors
|
||||
$this->manager->makeCollectionValid('BreadBased');
|
||||
$this->expectError('BreadBased collection is undefined');
|
||||
$this->manager->setup($config);
|
||||
}
|
||||
|
||||
function untest_soupStuff() {
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.Doctype' => 'The Soup Specification 8.0'
|
||||
));
|
||||
$this->manager->addModule($this->createModule('VegetablesModule'));
|
||||
$this->manager->addModule($this->createModule('MeatModule'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -107,7 +107,7 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness
|
||||
|
||||
$this->expectError('Cannot use unrecognized element as parent.');
|
||||
$this->assertResult(
|
||||
'<div>Accept</div>', true, array('HTML.Parent' => 'script')
|
||||
'<div>Accept</div>', true, array('HTML.Parent' => 'fling')
|
||||
);
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user