0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-03-11 17:18:44 +00:00

[1.7.0] Refactor HTMLModule unit tests

- AttrCollections does not barf when an inclusion is not present
- HTMLDefinition configuration directives now use new syntax
- Added %HTML.AllowedModules and %HTML.CoreModules for testing
- Extend Harness so that it can accept a default configuration object member variable
- Refactor modules to use Scaffolding, which defines some custom attributes that allows for the easy testing of attribute collections

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1082 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2007-05-20 22:29:31 +00:00
parent 2945f6a930
commit a470fc5621
12 changed files with 190 additions and 67 deletions

View File

@ -63,6 +63,7 @@ class HTMLPurifier_AttrCollections
if (isset($seen[$merge[$i]])) continue;
$seen[$merge[$i]] = true;
// foreach attribute of the inclusion, copy it over
if (!isset($this->info[$merge[$i]])) continue;
foreach ($this->info[$merge[$i]] as $key => $value) {
if (isset($attr[$key])) continue; // also catches more inclusions
$attr[$key] = $value;

View File

@ -7,48 +7,63 @@ require_once 'HTMLPurifier/HTMLModuleManager.php';
// outside of the HTML or Attr namespaces
HTMLPurifier_ConfigSchema::define(
'HTML', 'BlockWrapper', 'p', 'string',
'String name of element to wrap inline elements that are inside a block '.
'context. This only occurs in the children of blockquote in strict mode. '.
'Example: by default value, <code>&lt;blockquote&gt;Foo&lt;/blockquote&gt;</code> '.
'would become <code>&lt;blockquote&gt;&lt;p&gt;Foo&lt;/p&gt;&lt;/blockquote&gt;</code>. The '.
'<code>&lt;p&gt;</code> tags can be replaced '.
'with whatever you desire, as long as it is a block level element. '.
'This directive has been available since 1.3.0.'
);
'HTML', 'BlockWrapper', 'p', 'string', '
<p>
String name of element to wrap inline elements that are inside a block
context. This only occurs in the children of blockquote in strict mode.
</p>
<p>
Example: by default value,
<code>&lt;blockquote&gt;Foo&lt;/blockquote&gt;</code> would become
<code>&lt;blockquote&gt;&lt;p&gt;Foo&lt;/p&gt;&lt;/blockquote&gt;</code>.
The <code>&lt;p&gt;</code> tags can be replaced with whatever you desire,
as long as it is a block level element. This directive has been available
since 1.3.0.
</p>
');
HTMLPurifier_ConfigSchema::define(
'HTML', 'Parent', 'div', 'string',
'String name of element that HTML fragment passed to library will be '.
'inserted in. An interesting variation would be using span as the '.
'parent element, meaning that only inline tags would be allowed. '.
'This directive has been available since 1.3.0.'
);
'HTML', 'Parent', 'div', 'string', '
<p>
String name of element that HTML fragment passed to library will be
inserted in. An interesting variation would be using span as the
parent element, meaning that only inline tags would be allowed.
This directive has been available since 1.3.0.
</p>
');
HTMLPurifier_ConfigSchema::define(
'HTML', 'AllowedElements', null, 'lookup/null',
'If HTML Purifier\'s tag set is unsatisfactory for your needs, you '.
'can overload it with your own list of tags to allow. Note that this '.
'method is subtractive: it does its job by taking away from HTML Purifier '.
'usual feature set, so you cannot add a tag that HTML Purifier never '.
'supported in the first place (like embed, form or head). If you change this, you '.
'probably also want to change %HTML.AllowedAttributes. '.
'<strong>Warning:</strong> If another directive conflicts with the '.
'elements here, <em>that</em> directive will win and override. '.
'This directive has been available since 1.3.0.'
);
'HTML', 'AllowedElements', null, 'lookup/null', '
<p>
If HTML Purifier\'s tag set is unsatisfactory for your needs, you
can overload it with your own list of tags to allow. Note that this
method is subtractive: it does its job by taking away from HTML Purifier
usual feature set, so you cannot add a tag that HTML Purifier never
supported in the first place (like embed, form or head). If you
change this, you probably also want to change %HTML.AllowedAttributes.
</p>
<p>
<strong>Warning:</strong> If another directive conflicts with the
elements here, <em>that</em> directive will win and override.
This directive has been available since 1.3.0.
</p>
');
HTMLPurifier_ConfigSchema::define(
'HTML', 'AllowedAttributes', null, 'lookup/null',
'IF HTML Purifier\'s attribute set is unsatisfactory, overload it! '.
'The syntax is \'tag.attr\' or \'*.attr\' for the global attributes '.
'(style, id, class, dir, lang, xml:lang).'.
'<strong>Warning:</strong> If another directive conflicts with the '.
'elements here, <em>that</em> directive will win and override. For '.
'example, %HTML.EnableAttrID will take precedence over *.id in this '.
'directive. You must set that directive to true before you can use '.
'IDs at all. This directive has been available since 1.3.0.'
);
'HTML', 'AllowedAttributes', null, 'lookup/null', '
<p>
If HTML Purifier\'s attribute set is unsatisfactory, overload it!
The syntax is "tag.attr" or "*.attr" for the global attributes
(style, id, class, dir, lang, xml:lang).
</p>
<p>
<strong>Warning:</strong> If another directive conflicts with the
elements here, <em>that</em> directive will win and override. For
example, %HTML.EnableAttrID will take precedence over *.id in this
directive. You must set that directive to true before you can use
IDs at all. This directive has been available since 1.3.0.
</p>
');
/**
* Definition of the purified HTML that describes allowed children,

View File

@ -53,6 +53,43 @@ HTMLPurifier_ConfigSchema::define(
'will be used. This directive has been available since 1.7.0.'
);
HTMLPurifier_ConfigSchema::define(
'HTML', 'AllowedModules', null, 'lookup/null', '
<p>
A doctype comes with a set of usual modules to use. Without having
to mucking about with the doctypes, you can quickly activate or
disable these modules by specifying which modules you wish to allow
with this directive. This is most useful for unit testing specific
modules, although end users may find it useful for their own ends.
</p>
<p>
If you specify a module that does not exist, the manager will silently
fail to use it, so be careful! User-defined modules are not affected
by this directive. Modules defined in %HTML.CoreModules are not
affected by this directive. This directive has been available since 1.7.0.
</p>
');
HTMLPurifier_ConfigSchema::define(
'HTML', 'CoreModules', array(
'Structure' => true,
'Text' => true,
'Hypertext' => true,
'List' => true,
'NonXMLCommonAttributes' => true,
'XMLCommonAttributes' => true,
'CommonAttributes' => true
), 'lookup', '
<p>
Certain modularized doctypes (XHTML, namely), have certain modules
that must be included for the doctype to be an conforming document
type: put those modules here. By default, XHTML\'s core modules
are used. You can set this to a blank array to disable core module
protection, but this is not recommended. This directive has been
available since 1.7.0.
</p>
');
class HTMLPurifier_HTMLModuleManager
{
@ -254,6 +291,17 @@ class HTMLPurifier_HTMLModuleManager
$doctype = $this->doctypes->make($config);
$modules = $doctype->modules;
// take out the default modules that aren't allowed
$lookup = $config->get('HTML', 'AllowedModules');
$special_cases = $config->get('HTML', 'CoreModules');
if (is_array($lookup)) {
foreach ($modules as $k => $m) {
if (isset($special_cases[$m])) continue;
if (!isset($lookup[$m])) unset($modules[$k]);
}
}
// merge in custom modules
$modules = array_merge($modules, $this->userModules);
@ -291,7 +339,6 @@ class HTMLPurifier_HTMLModuleManager
// the module in your custom doctype should be sufficient
$this->modules
);
}
/**

View File

@ -70,7 +70,7 @@ class HTMLPurifier_AttrCollectionsTest extends UnitTestCase
$types = new HTMLPurifier_AttrTypesMock($this);
$collections = new HTMLPurifier_AttrCollections($types, array());
$collections->info = array(
'Core' => array(0 => array('Inclusion'), 'attr-original' => 'Type'),
'Core' => array(0 => array('Inclusion', 'Undefined'), 'attr-original' => 'Type'),
'Inclusion' => array(0 => array('SubInclusion'), 'attr' => 'Type'),
'SubInclusion' => array('attr2' => 'Type')
);

View File

@ -7,21 +7,15 @@ class HTMLPurifier_HTMLModule_BdoTest extends HTMLPurifier_HTMLModuleHarness
function test() {
$this->setupScaffold('Bdo');
// max
$this->assertResult(
'<span>
<bdo
id="test-id"
class="class-name"
style="font-weight:bold;"
title="Title of tag"
lang="en"
xml:lang="en"
dir="rtl"
>
<bdo ac:core="yes" dir="rtl">
#PCDATA <span>Inline</span>
</bdo>
</span>', true, array('Attr.EnableID' => true)
</span>'
);
// min

View File

@ -7,21 +7,23 @@ class HTMLPurifier_HTMLModule_EditTest extends HTMLPurifier_HTMLModuleHarness
function test() {
$this->setupScaffold('Edit');
// max
$this->assertResult(
'<span>
<ins cite="http://www.example.com/">
<ins cite="http://www.example.com/" ac:common="yes">
#PCDATA <span></span>
</ins>
<del cite="http://www.example.com/">
<del cite="http://www.example.com/" ac:common="yes">
#PCDATA <span></span>
</del>
</span>
<div>
<ins cite="http://www.example.com/">
<ins cite="http://www.example.com/" ac:common="yes">
#PCDATA <div></div> <span></span>
</ins>
<del cite="http://www.example.com/">
<del cite="http://www.example.com/" ac:common="yes">
#PCDATA <div></div> <span></span>
</del>
</div>'

View File

@ -7,6 +7,11 @@ class HTMLPurifier_HTMLModule_HypertextTest extends HTMLPurifier_HTMLModuleHarne
function test() {
$this->setupScaffold('Hypertext', array(
'Attr.AllowedRel' => 'nofollow',
'Attr.AllowedRev' => 'index'
));
// max
$this->assertResult(
'<span>
@ -14,13 +19,11 @@ class HTMLPurifier_HTMLModule_HypertextTest extends HTMLPurifier_HTMLModuleHarne
href="http://www.example.com/"
rel="nofollow"
rev="index"
ac:common="true"
>
#PCDATA <span>Inline</span>
</a>
</span>', true, array(
'Attr.AllowedRel' => 'nofollow',
'Attr.AllowedRev' => 'index'
)
</span>', true
);
// invalid children

View File

@ -7,6 +7,8 @@ class HTMLPurifier_HTMLModule_ImageTest extends HTMLPurifier_HTMLModuleHarness
function test() {
$this->setupScaffold('Image');
// max
$this->assertResult(
'<span>
@ -16,6 +18,7 @@ class HTMLPurifier_HTMLModule_ImageTest extends HTMLPurifier_HTMLModuleHarness
longdesc="example.description.txt"
height="42"
width="42"
ac:common="yes"
/>
</span>'
);

View File

@ -7,12 +7,14 @@ class HTMLPurifier_HTMLModule_LegacyTest extends HTMLPurifier_HTMLModuleHarness
function test() {
$this->setupScaffold('Legacy');
// max
$this->assertResult(
'<span>
<u>Text<span></span></u>
<s>Text<span></span></s>
<strike>Text<span></span></strike>
<u ac:common="yes">Text<span></span></u>
<s ac:common="yes">Text<span></span></s>
<strike ac:common="yes">Text<span></span></strike>
</span>'
);

View File

@ -9,6 +9,27 @@ class HTMLPurifier_HTMLModuleHarness extends HTMLPurifier_StrategyHarness
parent::setup();
$this->obj = new HTMLPurifier_Strategy_Core();
}
function setupScaffold($module, $config = array()) {
$this->config = HTMLPurifier_Config::create($config);
$this->config->set('HTML', 'AllowedModules', $module);
$def =& $this->config->getHTMLDefinition(true);
$def->manager->addModule(new HTMLPurifier_HTMLModuleHarness_Scaffold());
}
}
/**
* Special module that defines scaffolding for easy unit testing
*/
class HTMLPurifier_HTMLModuleHarness_Scaffold extends HTMLPurifier_HTMLModule
{
var $name = 'Scaffold';
var $attr_collections = array(
'Common' => array('ac:common' => 'Text'),
'Core' => array('ac:core' => 'Text')
);
}
?>

View File

@ -72,6 +72,34 @@ class HTMLPurifier_HTMLModuleManagerTest extends UnitTestCase
}
function testAllowedModules() {
$manager = new HTMLPurifier_HTMLModuleManager();
$manager->doctypes->register(
'Fantasy Inventory 1.0', true,
array('Weapons', 'Magic')
);
// register these modules so it doesn't blow up
$weapons_module = new HTMLPurifier_HTMLModule();
$weapons_module->name = 'Weapons';
$manager->registerModule($weapons_module);
$magic_module = new HTMLPurifier_HTMLModule();
$magic_module->name = 'Magic';
$manager->registerModule($magic_module);
$config = HTMLPurifier_Config::create(array(
'HTML.Doctype' => 'Fantasy Inventory 1.0',
'HTML.AllowedModules' => 'Weapons'
));
$manager->setup($config);
$this->assertTrue( isset($manager->modules['Weapons']));
$this->assertFalse(isset($manager->modules['Magic']));
}
}
?>

View File

@ -42,6 +42,11 @@ class HTMLPurifier_Harness extends UnitTestCase
*/
var $generator;
/**
* Default config to fall back on if no config is available
*/
var $config;
function HTMLPurifier_Harness() {
$this->lexer = new HTMLPurifier_Lexer_DirectLex();
$this->generator = new HTMLPurifier_Generator();
@ -52,22 +57,24 @@ class HTMLPurifier_Harness extends UnitTestCase
* Asserts a specific result from a one parameter + config/context function
* @param $input Input parameter
* @param $expect Expectation
* @param $config_array Configuration array in form of
* Namespace.Directive => Value or an actual config
* object.
* @param $config Configuration array in form of Ns.Directive => Value.
* Has no effect if $this->config is set.
* @param $context_array Context array in form of Key => Value or an actual
* context object.
*/
function assertResult($input, $expect = true,
$config_array = array(), $context_array = array()
$config_array = false, $context_array = array()
) {
// setup config object
$config = HTMLPurifier_Config::createDefault();
$config->loadArray($config_array);
// setup config
if ($this->config) {
$config = HTMLPurifier_Config::create($this->config);
} else {
$config = HTMLPurifier_Config::create($config_array);
}
// setup context object. Note that we are operating on a copy of it!
// We will extend the test harness to allow you to do post-tests
// When necessary, extend the test harness to allow post-tests
// on the context object
$context = new HTMLPurifier_Context();
$context->loadArray($context_array);