Initial commit.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements an external test-case like RemoteTestCase that parses its
|
||||
* output from XML returned by a command line call
|
||||
*/
|
||||
class CliTestCase
|
||||
{
|
||||
public $_command;
|
||||
public $_out = false;
|
||||
public $_quiet = false;
|
||||
public $_errors = array();
|
||||
/**
|
||||
* @param $command Command to execute to retrieve XML
|
||||
* @param $xml Whether or not to suppress error messages
|
||||
*/
|
||||
public function __construct($command, $quiet = false) {
|
||||
$this->_command = $command;
|
||||
$this->_quiet = $quiet;
|
||||
}
|
||||
public function getLabel() {
|
||||
return $this->_command;
|
||||
}
|
||||
public function run(&$reporter) {
|
||||
if (!$this->_quiet) $reporter->paintFormattedMessage('Running ['.$this->_command.']');
|
||||
$xml = shell_exec($this->_command);
|
||||
if (! $xml) {
|
||||
if (!$this->_quiet) {
|
||||
trigger_error('Command did not have any output [' . $this->_command . ']');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$parser = &$this->_createParser($reporter);
|
||||
|
||||
set_error_handler(array($this, '_errorHandler'));
|
||||
$status = $parser->parse($xml);
|
||||
restore_error_handler();
|
||||
|
||||
if (! $status) {
|
||||
if (!$this->_quiet) {
|
||||
foreach ($this->_errors as $error) {
|
||||
list($no, $str, $file, $line) = $error;
|
||||
$reporter->paintFormattedMessage("Error $no: $str on line $line of $file");
|
||||
}
|
||||
$msg = "Command produced malformed XML: \n";
|
||||
if (strlen($xml) > 120) {
|
||||
$msg .= substr($xml, 0, 50) . "...\n\n[snip]\n\n..." . substr($xml, -50);
|
||||
} else {
|
||||
$msg .= $xml;
|
||||
}
|
||||
$reporter->paintFormattedMessage($msg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public function &_createParser(&$reporter) {
|
||||
$parser = new SimpleTestXmlParser($reporter);
|
||||
return $parser;
|
||||
}
|
||||
public function getSize() {
|
||||
return 1; // we don't know it
|
||||
}
|
||||
public function _errorHandler($a, $b, $c, $d) {
|
||||
$this->_errors[] = array($a, $b, $c, $d); // see set_error_handler()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Debugging tools.
|
||||
*
|
||||
* This file gives a developer a set of tools useful for performing code
|
||||
* consistency checks. This includes scoping code blocks to ensure that
|
||||
* only the interesting iteration of a loop gets outputted, a paint()
|
||||
* function that acts like var_dump() with pre tags, and conditional
|
||||
* printing.
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO
|
||||
* Integrate into SimpleTest so it tells us whether or not there were any
|
||||
not cleaned up debug calls.
|
||||
* Custom var_dump() that ignores blacklisted properties
|
||||
* DEPRECATE AND REMOVE ALL CALLS!
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* Convenience global functions. Corresponds to method on Debugger.
|
||||
*/
|
||||
function paint($mixed) {
|
||||
$Debugger =& Debugger::instance();
|
||||
return $Debugger->paint($mixed);
|
||||
}
|
||||
function paintIf($mixed, $conditional) {
|
||||
$Debugger =& Debugger::instance();
|
||||
return $Debugger->paintIf($mixed, $conditional);
|
||||
}
|
||||
function paintWhen($mixed, $scopes = array()) {
|
||||
$Debugger =& Debugger::instance();
|
||||
return $Debugger->paintWhen($mixed, $scopes);
|
||||
}
|
||||
function paintIfWhen($mixed, $conditional, $scopes = array()) {
|
||||
$Debugger =& Debugger::instance();
|
||||
return $Debugger->paintIfWhen($mixed, $conditional, $scopes);
|
||||
}
|
||||
function addScope($id = false) {
|
||||
$Debugger =& Debugger::instance();
|
||||
return $Debugger->addScope($id);
|
||||
}
|
||||
function removeScope($id) {
|
||||
$Debugger =& Debugger::instance();
|
||||
return $Debugger->removeScope($id);
|
||||
}
|
||||
function resetScopes() {
|
||||
$Debugger =& Debugger::instance();
|
||||
return $Debugger->resetScopes();
|
||||
}
|
||||
function isInScopes($array = array()) {
|
||||
$Debugger =& Debugger::instance();
|
||||
return $Debugger->isInScopes($array);
|
||||
}
|
||||
/**#@-*/
|
||||
|
||||
function printTokens($tokens, $index = null) {
|
||||
$string = '<pre>';
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
foreach ($tokens as $i => $token) {
|
||||
if ($index === $i) $string .= '[<strong>';
|
||||
$string .= "<sup>$i</sup>";
|
||||
$string .= $generator->escape($generator->generateFromToken($token));
|
||||
if ($index === $i) $string .= '</strong>]';
|
||||
}
|
||||
$string .= '</pre>';
|
||||
echo $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The debugging singleton. Most interesting stuff happens here.
|
||||
*/
|
||||
class Debugger
|
||||
{
|
||||
|
||||
public $shouldPaint = false;
|
||||
public $paints = 0;
|
||||
public $current_scopes = array();
|
||||
public $scope_nextID = 1;
|
||||
public $add_pre = true;
|
||||
|
||||
public function Debugger() {
|
||||
$this->add_pre = !extension_loaded('xdebug');
|
||||
}
|
||||
|
||||
public static function &instance() {
|
||||
static $soleInstance = false;
|
||||
if (!$soleInstance) $soleInstance = new Debugger();
|
||||
return $soleInstance;
|
||||
}
|
||||
|
||||
public function paintIf($mixed, $conditional) {
|
||||
if (!$conditional) return;
|
||||
$this->paint($mixed);
|
||||
}
|
||||
|
||||
public function paintWhen($mixed, $scopes = array()) {
|
||||
if (!$this->isInScopes($scopes)) return;
|
||||
$this->paint($mixed);
|
||||
}
|
||||
|
||||
public function paintIfWhen($mixed, $conditional, $scopes = array()) {
|
||||
if (!$conditional) return;
|
||||
if (!$this->isInScopes($scopes)) return;
|
||||
$this->paint($mixed);
|
||||
}
|
||||
|
||||
public function paint($mixed) {
|
||||
$this->paints++;
|
||||
if($this->add_pre) echo '<pre>';
|
||||
var_dump($mixed);
|
||||
if($this->add_pre) echo '</pre>';
|
||||
}
|
||||
|
||||
public function addScope($id = false) {
|
||||
if ($id == false) {
|
||||
$id = $this->scope_nextID++;
|
||||
}
|
||||
$this->current_scopes[$id] = true;
|
||||
}
|
||||
|
||||
public function removeScope($id) {
|
||||
if (isset($this->current_scopes[$id])) unset($this->current_scopes[$id]);
|
||||
}
|
||||
|
||||
public function resetScopes() {
|
||||
$this->current_scopes = array();
|
||||
$this->scope_nextID = 1;
|
||||
}
|
||||
|
||||
public function isInScopes($scopes = array()) {
|
||||
if (empty($this->current_scopes)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_array($scopes)) {
|
||||
$scopes = array($scopes);
|
||||
}
|
||||
foreach ($scopes as $scope_id) {
|
||||
if (empty($this->current_scopes[$scope_id])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (empty($scopes)) {
|
||||
if ($this->scope_nextID == 1) {
|
||||
return false;
|
||||
}
|
||||
for($i = 1; $i < $this->scope_nextID; $i++) {
|
||||
if (empty($this->current_scopes[$i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrCollections.php';
|
||||
|
||||
Mock::generatePartial(
|
||||
'HTMLPurifier_AttrCollections',
|
||||
'HTMLPurifier_AttrCollections_TestForConstruct',
|
||||
array('performInclusions', 'expandIdentifiers')
|
||||
);
|
||||
|
||||
class HTMLPurifier_AttrCollectionsTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function testConstruction() {
|
||||
|
||||
generate_mock_once('HTMLPurifier_AttrTypes');
|
||||
|
||||
$collections = new HTMLPurifier_AttrCollections_TestForConstruct();
|
||||
|
||||
$types = new HTMLPurifier_AttrTypesMock();
|
||||
|
||||
$modules = array();
|
||||
|
||||
$modules['Module1'] = new HTMLPurifier_HTMLModule();
|
||||
$modules['Module1']->attr_collections = array(
|
||||
'Core' => array(
|
||||
0 => array('Soup', 'Undefined'),
|
||||
'attribute' => 'Type',
|
||||
'attribute-2' => 'Type2',
|
||||
),
|
||||
'Soup' => array(
|
||||
'attribute-3' => 'Type3-old' // overwritten
|
||||
)
|
||||
);
|
||||
|
||||
$modules['Module2'] = new HTMLPurifier_HTMLModule();
|
||||
$modules['Module2']->attr_collections = array(
|
||||
'Core' => array(
|
||||
0 => array('Brocolli')
|
||||
),
|
||||
'Soup' => array(
|
||||
'attribute-3' => 'Type3'
|
||||
),
|
||||
'Brocolli' => array()
|
||||
);
|
||||
|
||||
$collections->__construct($types, $modules);
|
||||
// this is without identifier expansion or inclusions
|
||||
$this->assertIdentical(
|
||||
$collections->info,
|
||||
array(
|
||||
'Core' => array(
|
||||
0 => array('Soup', 'Undefined', 'Brocolli'),
|
||||
'attribute' => 'Type',
|
||||
'attribute-2' => 'Type2'
|
||||
),
|
||||
'Soup' => array(
|
||||
'attribute-3' => 'Type3'
|
||||
),
|
||||
'Brocolli' => array()
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_performInclusions() {
|
||||
|
||||
generate_mock_once('HTMLPurifier_AttrTypes');
|
||||
|
||||
$types = new HTMLPurifier_AttrTypesMock();
|
||||
$collections = new HTMLPurifier_AttrCollections($types, array());
|
||||
$collections->info = array(
|
||||
'Core' => array(0 => array('Inclusion', 'Undefined'), 'attr-original' => 'Type'),
|
||||
'Inclusion' => array(0 => array('SubInclusion'), 'attr' => 'Type'),
|
||||
'SubInclusion' => array('attr2' => 'Type')
|
||||
);
|
||||
|
||||
$collections->performInclusions($collections->info['Core']);
|
||||
$this->assertIdentical(
|
||||
$collections->info['Core'],
|
||||
array(
|
||||
'attr-original' => 'Type',
|
||||
'attr' => 'Type',
|
||||
'attr2' => 'Type'
|
||||
)
|
||||
);
|
||||
|
||||
// test recursive
|
||||
$collections->info = array(
|
||||
'One' => array(0 => array('Two'), 'one' => 'Type'),
|
||||
'Two' => array(0 => array('One'), 'two' => 'Type')
|
||||
);
|
||||
$collections->performInclusions($collections->info['One']);
|
||||
$this->assertIdentical(
|
||||
$collections->info['One'],
|
||||
array(
|
||||
'one' => 'Type',
|
||||
'two' => 'Type'
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_expandIdentifiers() {
|
||||
|
||||
generate_mock_once('HTMLPurifier_AttrTypes');
|
||||
|
||||
$types = new HTMLPurifier_AttrTypesMock();
|
||||
$collections = new HTMLPurifier_AttrCollections($types, array());
|
||||
|
||||
$attr = array(
|
||||
'attr1' => 'Color',
|
||||
'attr2*' => 'URI'
|
||||
);
|
||||
$c_object = new HTMLPurifier_AttrDef_HTML_Color();
|
||||
$u_object = new HTMLPurifier_AttrDef_URI();
|
||||
|
||||
$types->setReturnValue('get', $c_object, array('Color'));
|
||||
$types->setReturnValue('get', $u_object, array('URI'));
|
||||
|
||||
$collections->expandIdentifiers($attr, $types);
|
||||
|
||||
$u_object->required = true;
|
||||
$this->assertIdentical(
|
||||
$attr,
|
||||
array(
|
||||
'attr1' => $c_object,
|
||||
'attr2' => $u_object
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/AlphaValue.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_AlphaValueTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_AlphaValue();
|
||||
|
||||
$this->assertDef('0');
|
||||
$this->assertDef('1');
|
||||
$this->assertDef('.2');
|
||||
|
||||
// clamping to [0.0, 1,0]
|
||||
$this->assertDef('1.2', '1');
|
||||
$this->assertDef('-3', '0');
|
||||
|
||||
$this->assertDef('0.0', '0');
|
||||
$this->assertDef('1.0', '1');
|
||||
$this->assertDef('000', '0');
|
||||
|
||||
$this->assertDef('asdf', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/BackgroundPosition.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_BackgroundPositionTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_BackgroundPosition();
|
||||
|
||||
// explicitly cited in spec
|
||||
$this->assertDef('0% 0%');
|
||||
$this->assertDef('100% 100%');
|
||||
$this->assertDef('14% 84%');
|
||||
$this->assertDef('2cm 1cm');
|
||||
$this->assertDef('top');
|
||||
$this->assertDef('left');
|
||||
$this->assertDef('center');
|
||||
$this->assertDef('right');
|
||||
$this->assertDef('bottom');
|
||||
$this->assertDef('left top');
|
||||
$this->assertDef('center top');
|
||||
$this->assertDef('right top');
|
||||
$this->assertDef('left center');
|
||||
$this->assertDef('right center');
|
||||
$this->assertDef('left bottom');
|
||||
$this->assertDef('center bottom');
|
||||
$this->assertDef('right bottom');
|
||||
|
||||
// reordered due to internal impl details
|
||||
$this->assertDef('top left', 'left top');
|
||||
$this->assertDef('top center', 'center top');
|
||||
$this->assertDef('top right', 'right top');
|
||||
$this->assertDef('center left', 'left center');
|
||||
$this->assertDef('center center', 'center'); // two centers collide
|
||||
$this->assertDef('center right', 'right center');
|
||||
$this->assertDef('bottom left', 'left bottom');
|
||||
$this->assertDef('bottom center', 'center bottom');
|
||||
$this->assertDef('bottom right', 'right bottom');
|
||||
|
||||
// more cases from the defined syntax
|
||||
$this->assertDef('1.32in 4ex');
|
||||
$this->assertDef('-14% -84.65%');
|
||||
$this->assertDef('-1in -4ex');
|
||||
$this->assertDef('-1pc 2.3%');
|
||||
|
||||
// keyword mixing
|
||||
$this->assertDef('3em top');
|
||||
$this->assertDef('left 50%');
|
||||
|
||||
// fixable keyword mixing
|
||||
$this->assertDef('top 3em', '3em top');
|
||||
$this->assertDef('50% left', 'left 50%');
|
||||
|
||||
// whitespace collapsing
|
||||
$this->assertDef('3em top', '3em top');
|
||||
$this->assertDef("left\n \t foo ", 'left');
|
||||
|
||||
// invalid uses (we're going to be strict on these)
|
||||
$this->assertDef('foo bar', false);
|
||||
$this->assertDef('left left', 'left');
|
||||
$this->assertDef('left right top bottom center left', 'left bottom');
|
||||
$this->assertDef('0fr 9%', '9%');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Background.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_BackgroundTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Background($config);
|
||||
|
||||
$valid = '#333 url(chess.png) repeat fixed 50% top';
|
||||
$this->assertDef($valid);
|
||||
$this->assertDef('url("chess.png") #333 50% top repeat fixed', $valid);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Border.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_BorderTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Border($config);
|
||||
|
||||
$this->assertDef('thick solid red', 'thick solid #FF0000');
|
||||
$this->assertDef('thick solid');
|
||||
$this->assertDef('solid red', 'solid #FF0000');
|
||||
$this->assertDef('1px solid #000');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Color.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_ColorTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Color();
|
||||
|
||||
$this->assertDef('#F00');
|
||||
$this->assertDef('#fff');
|
||||
$this->assertDef('#eeeeee');
|
||||
$this->assertDef('#808080');
|
||||
$this->assertDef('rgb(255, 0, 0)', 'rgb(255,0,0)'); // rm spaces
|
||||
$this->assertDef('rgb(100%,0%,0%)');
|
||||
$this->assertDef('rgb(50.5%,23.2%,43.9%)'); // decimals okay
|
||||
|
||||
$this->assertDef('#G00', false);
|
||||
$this->assertDef('cmyk(40, 23, 43, 23)', false);
|
||||
$this->assertDef('rgb(0%, 23, 68%)', false);
|
||||
|
||||
// clip numbers outside sRGB gamut
|
||||
$this->assertDef('rgb(200%, -10%, 0%)', 'rgb(100%,0%,0%)');
|
||||
$this->assertDef('rgb(256,-23,34)', 'rgb(255,0,34)');
|
||||
|
||||
// color keywords, of course
|
||||
$this->assertDef('red', '#FF0000');
|
||||
|
||||
// malformed hex declaration
|
||||
$this->assertDef('808080', '#808080');
|
||||
$this->assertDef('000000', '#000000');
|
||||
$this->assertDef('fed', '#fed');
|
||||
|
||||
// maybe hex transformations would be another nice feature
|
||||
// at the very least transform rgb percent to rgb integer
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Composite.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_Composite_Testable extends
|
||||
HTMLPurifier_AttrDef_CSS_Composite
|
||||
{
|
||||
|
||||
// we need to pass by ref to get the mocks in
|
||||
function HTMLPurifier_AttrDef_CSS_Composite_Testable(&$defs) {
|
||||
$this->defs =& $defs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_CompositeTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
protected $def1, $def2;
|
||||
|
||||
function test() {
|
||||
|
||||
generate_mock_once('HTMLPurifier_AttrDef');
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$context = new HTMLPurifier_Context();
|
||||
|
||||
// first test: value properly validates on first definition
|
||||
// so second def is never called
|
||||
|
||||
$def1 = new HTMLPurifier_AttrDefMock();
|
||||
$def2 = new HTMLPurifier_AttrDefMock();
|
||||
$defs = array(&$def1, &$def2);
|
||||
$def = new HTMLPurifier_AttrDef_CSS_Composite_Testable($defs);
|
||||
$input = 'FOOBAR';
|
||||
$output = 'foobar';
|
||||
$def1_params = array($input, $config, $context);
|
||||
$def1->expectOnce('validate', $def1_params);
|
||||
$def1->setReturnValue('validate', $output, $def1_params);
|
||||
$def2->expectNever('validate');
|
||||
|
||||
$result = $def->validate($input, $config, $context);
|
||||
$this->assertIdentical($output, $result);
|
||||
|
||||
$def1->tally();
|
||||
$def2->tally();
|
||||
|
||||
// second test, first def fails, second def works
|
||||
|
||||
$def1 = new HTMLPurifier_AttrDefMock();
|
||||
$def2 = new HTMLPurifier_AttrDefMock();
|
||||
$defs = array(&$def1, &$def2);
|
||||
$def = new HTMLPurifier_AttrDef_CSS_Composite_Testable($defs);
|
||||
$input = 'BOOMA';
|
||||
$output = 'booma';
|
||||
$def_params = array($input, $config, $context);
|
||||
$def1->expectOnce('validate', $def_params);
|
||||
$def1->setReturnValue('validate', false, $def_params);
|
||||
$def2->expectOnce('validate', $def_params);
|
||||
$def2->setReturnValue('validate', $output, $def_params);
|
||||
|
||||
$result = $def->validate($input, $config, $context);
|
||||
$this->assertIdentical($output, $result);
|
||||
|
||||
$def1->tally();
|
||||
$def2->tally();
|
||||
|
||||
// third test, all fail, so composite faiils
|
||||
|
||||
$def1 = new HTMLPurifier_AttrDefMock();
|
||||
$def2 = new HTMLPurifier_AttrDefMock();
|
||||
$defs = array(&$def1, &$def2);
|
||||
$def = new HTMLPurifier_AttrDef_CSS_Composite_Testable($defs);
|
||||
$input = 'BOOMA';
|
||||
$output = false;
|
||||
$def_params = array($input, $config, $context);
|
||||
$def1->expectOnce('validate', $def_params);
|
||||
$def1->setReturnValue('validate', false, $def_params);
|
||||
$def2->expectOnce('validate', $def_params);
|
||||
$def2->setReturnValue('validate', false, $def_params);
|
||||
|
||||
$result = $def->validate($input, $config, $context);
|
||||
$this->assertIdentical($output, $result);
|
||||
|
||||
$def1->tally();
|
||||
$def2->tally();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Filter.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_FilterTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Filter();
|
||||
|
||||
$this->assertDef('none');
|
||||
|
||||
$this->assertDef('alpha(opacity=0)');
|
||||
$this->assertDef('alpha(opacity=100)');
|
||||
$this->assertDef('alpha(opacity=50)');
|
||||
$this->assertDef('alpha(opacity=342)', 'alpha(opacity=100)');
|
||||
$this->assertDef('alpha(opacity=-23)', 'alpha(opacity=0)');
|
||||
|
||||
$this->assertDef('alpha ( opacity = 0 )', 'alpha(opacity=0)');
|
||||
$this->assertDef('alpha(opacity=0,opacity=100)', 'alpha(opacity=0)');
|
||||
|
||||
$this->assertDef('progid:DXImageTransform.Microsoft.Alpha(opacity=20)');
|
||||
|
||||
$this->assertDef('progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/FontFamily.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_FontFamilyTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_FontFamily();
|
||||
|
||||
$this->assertDef('Gill, Helvetica, sans-serif');
|
||||
$this->assertDef('\'Times New Roman\', serif');
|
||||
$this->assertDef('"Times New Roman"', "'Times New Roman'");
|
||||
$this->assertDef('01234');
|
||||
$this->assertDef(',', false);
|
||||
$this->assertDef('Times New Roman, serif', '\'Times New Roman\', serif');
|
||||
$this->assertDef($d = "'John\\'s Font'");
|
||||
$this->assertDef("John's Font", $d);
|
||||
$this->assertDef($d = "'\xE5\xAE\x8B\xE4\xBD\x93'");
|
||||
$this->assertDef("\xE5\xAE\x8B\xE4\xBD\x93", $d);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Font.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_FontTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Font($config);
|
||||
|
||||
// hodgepodge of usage cases from W3C spec, but " -> '
|
||||
$this->assertDef('12px/14px sans-serif');
|
||||
$this->assertDef('80% sans-serif');
|
||||
$this->assertDef('x-large/110% \'New Century Schoolbook\', serif');
|
||||
$this->assertDef('bold italic large Palatino, serif');
|
||||
$this->assertDef('normal small-caps 120%/120% fantasy');
|
||||
$this->assertDef('300 italic 1.3em/1.7em \'FB Armada\', sans-serif');
|
||||
$this->assertDef('600 9px Charcoal');
|
||||
$this->assertDef('600 9px/ 12px Charcoal', '600 9px/12px Charcoal');
|
||||
|
||||
// spacing
|
||||
$this->assertDef('12px / 14px sans-serif', '12px/14px sans-serif');
|
||||
|
||||
// system fonts
|
||||
$this->assertDef('menu');
|
||||
|
||||
$this->assertDef('800', false);
|
||||
$this->assertDef('600 9px//12px Charcoal', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Length.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_LengthTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Length();
|
||||
|
||||
$this->assertDef('0');
|
||||
$this->assertDef('0px');
|
||||
$this->assertDef('4.5px');
|
||||
$this->assertDef('-4.5px');
|
||||
$this->assertDef('3ex');
|
||||
$this->assertDef('3em');
|
||||
$this->assertDef('3in');
|
||||
$this->assertDef('3cm');
|
||||
$this->assertDef('3mm');
|
||||
$this->assertDef('3pt');
|
||||
$this->assertDef('3pc');
|
||||
|
||||
$this->assertDef('3PX', '3px');
|
||||
|
||||
$this->assertDef('3', false);
|
||||
$this->assertDef('3miles', false);
|
||||
|
||||
}
|
||||
|
||||
function testNonNegative() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Length(true);
|
||||
|
||||
$this->assertDef('3cm');
|
||||
$this->assertDef('-3mm', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/ListStyle.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_ListStyleTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_ListStyle($config);
|
||||
|
||||
$this->assertDef('lower-alpha');
|
||||
$this->assertDef('upper-roman inside');
|
||||
$this->assertDef('circle outside');
|
||||
$this->assertDef('inside');
|
||||
$this->assertDef('none');
|
||||
$this->assertDef('url(foo.gif)');
|
||||
$this->assertDef('circle url(foo.gif) inside');
|
||||
|
||||
// invalid values
|
||||
$this->assertDef('outside inside', 'outside');
|
||||
|
||||
// ordering
|
||||
$this->assertDef('url(foo.gif) none', 'none url(foo.gif)');
|
||||
$this->assertDef('circle lower-alpha', 'circle');
|
||||
// the spec is ambiguous about what happens in these
|
||||
// cases, so we're going off the W3C CSS validator
|
||||
$this->assertDef('disc none', 'disc');
|
||||
$this->assertDef('none disc', 'none');
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Multiple.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
// borrowed for the sakes of this test
|
||||
require_once 'HTMLPurifier/AttrDef/Integer.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_MultipleTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Multiple(
|
||||
new HTMLPurifier_AttrDef_Integer()
|
||||
);
|
||||
|
||||
$this->assertDef('1 2 3 4');
|
||||
$this->assertDef('6');
|
||||
$this->assertDef('4 5');
|
||||
$this->assertDef(' 2 54 2 3', '2 54 2 3');
|
||||
$this->assertDef("6\r3", '6 3');
|
||||
|
||||
$this->assertDef('asdf', false);
|
||||
$this->assertDef('a s d f', false);
|
||||
$this->assertDef('1 2 3 4 5', '1 2 3 4');
|
||||
$this->assertDef('1 2 invalid 3', '1 2 3');
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Number.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_NumberTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Number();
|
||||
|
||||
$this->assertDef('0');
|
||||
$this->assertDef('0.0', '0');
|
||||
$this->assertDef('1.0', '1');
|
||||
$this->assertDef('34');
|
||||
$this->assertDef('4.5');
|
||||
$this->assertDef('.5');
|
||||
$this->assertDef('0.5', '.5');
|
||||
$this->assertDef('-56.9');
|
||||
|
||||
$this->assertDef('0.', '0');
|
||||
$this->assertDef('.0', '0');
|
||||
$this->assertDef('0.0', '0');
|
||||
|
||||
$this->assertDef('1.', '1');
|
||||
$this->assertDef('.1', '.1');
|
||||
|
||||
$this->assertDef('1.0', '1');
|
||||
$this->assertDef('0.1', '.1');
|
||||
|
||||
$this->assertDef('000', '0');
|
||||
$this->assertDef(' 9', '9');
|
||||
$this->assertDef('+5.0000', '5');
|
||||
$this->assertDef('02.20', '2.2');
|
||||
$this->assertDef('2.', '2');
|
||||
|
||||
$this->assertDef('.', false);
|
||||
$this->assertDef('asdf', false);
|
||||
$this->assertDef('0.5.6', false);
|
||||
|
||||
}
|
||||
|
||||
function testNonNegative() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Number(true);
|
||||
$this->assertDef('23');
|
||||
$this->assertDef('-12', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/Percentage.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_PercentageTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_Percentage();
|
||||
|
||||
$this->assertDef('10%');
|
||||
$this->assertDef('1.607%');
|
||||
$this->assertDef('-567%');
|
||||
|
||||
$this->assertDef(' 100% ', '100%');
|
||||
|
||||
$this->assertDef('5', false);
|
||||
$this->assertDef('asdf', false);
|
||||
$this->assertDef('%', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/TextDecoration.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_TextDecorationTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function testCaseInsensitive() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_TextDecoration();
|
||||
|
||||
$this->assertDef('underline');
|
||||
$this->assertDef('overline');
|
||||
$this->assertDef('line-through overline underline');
|
||||
$this->assertDef('overline line-through');
|
||||
$this->assertDef('UNDERLINE', 'underline');
|
||||
$this->assertDef(' underline line-through ', 'underline line-through');
|
||||
|
||||
$this->assertDef('foobar underline', 'underline');
|
||||
$this->assertDef('blink', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS/URI.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSS_URITest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS_URI();
|
||||
|
||||
$this->assertDef('', false);
|
||||
|
||||
// we could be nice but we won't be
|
||||
$this->assertDef('http://www.example.com/', false);
|
||||
|
||||
// no quotes are used, since that's the most widely supported
|
||||
// syntax
|
||||
$this->assertDef('url(', false);
|
||||
$this->assertDef('url()', true);
|
||||
$result = "url(http://www.example.com/)";
|
||||
$this->assertDef('url(http://www.example.com/)', $result);
|
||||
$this->assertDef('url("http://www.example.com/")', $result);
|
||||
$this->assertDef("url('http://www.example.com/')", $result);
|
||||
$this->assertDef(
|
||||
' url( "http://www.example.com/" ) ', $result);
|
||||
|
||||
// escaping
|
||||
$this->assertDef("url(http://www.example.com/foo,bar\))",
|
||||
"url(http://www.example.com/foo\,bar\))");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/CSS.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_CSSTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS();
|
||||
|
||||
// regular cases, singular
|
||||
$this->assertDef('text-align:right;');
|
||||
$this->assertDef('border-left-style:solid;');
|
||||
$this->assertDef('border-style:solid dotted;');
|
||||
$this->assertDef('clear:right;');
|
||||
$this->assertDef('float:left;');
|
||||
$this->assertDef('font-style:italic;');
|
||||
$this->assertDef('font-variant:small-caps;');
|
||||
$this->assertDef('font-weight:bold;');
|
||||
$this->assertDef('list-style-position:outside;');
|
||||
$this->assertDef('list-style-type:upper-roman;');
|
||||
$this->assertDef('list-style:upper-roman inside;');
|
||||
$this->assertDef('text-transform:capitalize;');
|
||||
$this->assertDef('background-color:rgb(0,0,255);');
|
||||
$this->assertDef('background-color:transparent;');
|
||||
$this->assertDef('background:#333 url(chess.png) repeat fixed 50% top;');
|
||||
$this->assertDef('color:#F00;');
|
||||
$this->assertDef('border-top-color:#F00;');
|
||||
$this->assertDef('border-color:#F00 #FF0;');
|
||||
$this->assertDef('border-top-width:thin;');
|
||||
$this->assertDef('border-top-width:12px;');
|
||||
$this->assertDef('border-width:5px 1px 4px 2px;');
|
||||
$this->assertDef('border-top-width:-12px;', false);
|
||||
$this->assertDef('letter-spacing:normal;');
|
||||
$this->assertDef('letter-spacing:2px;');
|
||||
$this->assertDef('word-spacing:normal;');
|
||||
$this->assertDef('word-spacing:3em;');
|
||||
$this->assertDef('font-size:200%;');
|
||||
$this->assertDef('font-size:larger;');
|
||||
$this->assertDef('font-size:12pt;');
|
||||
$this->assertDef('line-height:2;');
|
||||
$this->assertDef('line-height:2em;');
|
||||
$this->assertDef('line-height:20%;');
|
||||
$this->assertDef('line-height:normal;');
|
||||
$this->assertDef('line-height:-20%;', false);
|
||||
$this->assertDef('margin-left:5px;');
|
||||
$this->assertDef('margin-right:20%;');
|
||||
$this->assertDef('margin-top:auto;');
|
||||
$this->assertDef('margin:auto 5%;');
|
||||
$this->assertDef('padding-bottom:5px;');
|
||||
$this->assertDef('padding-top:20%;');
|
||||
$this->assertDef('padding:20% 10%;');
|
||||
$this->assertDef('padding-top:-20%;', false);
|
||||
$this->assertDef('text-indent:3em;');
|
||||
$this->assertDef('text-indent:5%;');
|
||||
$this->assertDef('text-indent:-3em;');
|
||||
$this->assertDef('width:50%;');
|
||||
$this->assertDef('width:50px;');
|
||||
$this->assertDef('width:auto;');
|
||||
$this->assertDef('width:-50px;', false);
|
||||
$this->assertDef('text-decoration:underline;');
|
||||
$this->assertDef('font-family:sans-serif;');
|
||||
$this->assertDef('font-family:Gill, \'Times New Roman\', sans-serif;');
|
||||
$this->assertDef('font:12px serif;');
|
||||
$this->assertDef('border:1px solid #000;');
|
||||
$this->assertDef('border-bottom:2em double #FF00FA;');
|
||||
$this->assertDef('border-collapse:collapse;');
|
||||
$this->assertDef('border-collapse:separate;');
|
||||
$this->assertDef('caption-side:top;');
|
||||
$this->assertDef('vertical-align:middle;');
|
||||
$this->assertDef('vertical-align:12px;');
|
||||
$this->assertDef('vertical-align:50%;');
|
||||
$this->assertDef('table-layout:fixed;');
|
||||
$this->assertDef('list-style-image:url(nice.jpg);');
|
||||
$this->assertDef('list-style:disc url(nice.jpg) inside;');
|
||||
$this->assertDef('background-image:url(foo.jpg);');
|
||||
$this->assertDef('background-image:none;');
|
||||
$this->assertDef('background-repeat:repeat-y;');
|
||||
$this->assertDef('background-attachment:fixed;');
|
||||
$this->assertDef('background-position:left 90%;');
|
||||
$this->assertDef('border-spacing:1em;');
|
||||
$this->assertDef('border-spacing:1em 2em;');
|
||||
|
||||
// duplicates
|
||||
$this->assertDef('text-align:right;text-align:left;',
|
||||
'text-align:left;');
|
||||
|
||||
// a few composites
|
||||
$this->assertDef('font-variant:small-caps;font-weight:900;');
|
||||
$this->assertDef('float:right;text-align:right;');
|
||||
|
||||
// selective removal
|
||||
$this->assertDef('text-transform:capitalize;destroy:it;',
|
||||
'text-transform:capitalize;');
|
||||
|
||||
// inherit works for everything
|
||||
$this->assertDef('text-align:inherit;');
|
||||
|
||||
// bad props
|
||||
$this->assertDef('nodice:foobar;', false);
|
||||
$this->assertDef('position:absolute;', false);
|
||||
$this->assertDef('background-image:url(javascript:alert\(\));', false);
|
||||
|
||||
// airy input
|
||||
$this->assertDef(' font-weight : bold; color : #ff0000',
|
||||
'font-weight:bold;color:#ff0000;');
|
||||
|
||||
// case-insensitivity
|
||||
$this->assertDef('FLOAT:LEFT;', 'float:left;');
|
||||
|
||||
}
|
||||
|
||||
function testProprietary() {
|
||||
$this->config->set('CSS', 'Proprietary', true);
|
||||
$this->def = new HTMLPurifier_AttrDef_CSS();
|
||||
|
||||
$this->assertDef('scrollbar-arrow-color:#ff0;');
|
||||
$this->assertDef('scrollbar-base-color:#ff6347;');
|
||||
$this->assertDef('scrollbar-darkshadow-color:#ffa500;');
|
||||
$this->assertDef('scrollbar-face-color:#008080;');
|
||||
$this->assertDef('scrollbar-highlight-color:#ff69b4;');
|
||||
$this->assertDef('scrollbar-shadow-color:#f0f;');
|
||||
|
||||
$this->assertDef('opacity:.2;');
|
||||
$this->assertDef('-moz-opacity:.2;');
|
||||
$this->assertDef('-khtml-opacity:.2;');
|
||||
$this->assertDef('filter:alpha(opacity=20);');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/Enum.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_EnumTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function testCaseInsensitive() {
|
||||
$this->def = new HTMLPurifier_AttrDef_Enum(array('one', 'two'));
|
||||
$this->assertDef('one');
|
||||
$this->assertDef('ONE', 'one');
|
||||
}
|
||||
|
||||
function testCaseSensitive() {
|
||||
$this->def = new HTMLPurifier_AttrDef_Enum(array('one', 'two'), true);
|
||||
$this->assertDef('one');
|
||||
$this->assertDef('ONE', false);
|
||||
}
|
||||
|
||||
function testFixing() {
|
||||
$this->def = new HTMLPurifier_AttrDef_Enum(array('one'));
|
||||
$this->assertDef(' one ', 'one');
|
||||
}
|
||||
|
||||
function test_make() {
|
||||
$factory = new HTMLPurifier_AttrDef_Enum();
|
||||
|
||||
$def = $factory->make('foo,bar');
|
||||
$def2 = new HTMLPurifier_AttrDef_Enum(array('foo', 'bar'));
|
||||
$this->assertIdentical($def, $def2);
|
||||
|
||||
$def = $factory->make('s:foo,BAR');
|
||||
$def2 = new HTMLPurifier_AttrDef_Enum(array('foo', 'BAR'), true);
|
||||
$this->assertIdentical($def, $def2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/Bool.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_BoolTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_Bool('foo');
|
||||
$this->assertDef('foo');
|
||||
$this->assertDef('', false);
|
||||
$this->assertDef('bar', false);
|
||||
}
|
||||
|
||||
function test_make() {
|
||||
$factory = new HTMLPurifier_AttrDef_HTML_Bool();
|
||||
$def = $factory->make('foo');
|
||||
$def2 = new HTMLPurifier_AttrDef_HTML_Bool('foo');
|
||||
$this->assertIdentical($def, $def2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/Color.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_ColorTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_Color();
|
||||
$this->assertDef('', false);
|
||||
$this->assertDef('foo', false);
|
||||
$this->assertDef('43', false);
|
||||
$this->assertDef('red', '#FF0000');
|
||||
$this->assertDef('#FF0000');
|
||||
$this->assertDef('#453443');
|
||||
$this->assertDef('453443', '#453443');
|
||||
$this->assertDef('#345', '#334455');
|
||||
$this->assertDef('120', '#112200');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/FrameTarget.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_FrameTargetTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function setup() {
|
||||
parent::setup();
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_FrameTarget();
|
||||
}
|
||||
|
||||
function testNoneAllowed() {
|
||||
$this->assertDef('', false);
|
||||
$this->assertDef('foo', false);
|
||||
$this->assertDef('_blank', false);
|
||||
$this->assertDef('baz', false);
|
||||
}
|
||||
|
||||
function test() {
|
||||
$this->config->set('Attr', 'AllowedFrameTargets', 'foo,_blank');
|
||||
$this->assertDef('', false);
|
||||
$this->assertDef('foo');
|
||||
$this->assertDef('_blank');
|
||||
$this->assertDef('baz', false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/ID.php';
|
||||
require_once 'HTMLPurifier/IDAccumulator.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_IDTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$id_accumulator = new HTMLPurifier_IDAccumulator();
|
||||
$this->context->register('IDAccumulator', $id_accumulator);
|
||||
$this->config->set('Attr', 'EnableID', true);
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_ID();
|
||||
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
||||
// valid ID names
|
||||
$this->assertDef('alpha');
|
||||
$this->assertDef('al_ha');
|
||||
$this->assertDef('a0-:.');
|
||||
$this->assertDef('a');
|
||||
|
||||
// invalid ID names
|
||||
$this->assertDef('<asa', false);
|
||||
$this->assertDef('0123', false);
|
||||
$this->assertDef('.asa', false);
|
||||
|
||||
// test duplicate detection
|
||||
$this->assertDef('once');
|
||||
$this->assertDef('once', false);
|
||||
|
||||
// valid once whitespace stripped, but needs to be amended
|
||||
$this->assertDef(' whee ', 'whee');
|
||||
|
||||
}
|
||||
|
||||
function testPrefix() {
|
||||
|
||||
$this->config->set('Attr', 'IDPrefix', 'user_');
|
||||
|
||||
$this->assertDef('alpha', 'user_alpha');
|
||||
$this->assertDef('<asa', false);
|
||||
$this->assertDef('once', 'user_once');
|
||||
$this->assertDef('once', false);
|
||||
|
||||
// if already prefixed, leave alone
|
||||
$this->assertDef('user_alas');
|
||||
$this->assertDef('user_user_alas'); // how to bypass
|
||||
|
||||
}
|
||||
|
||||
function testTwoPrefixes() {
|
||||
|
||||
$this->config->set('Attr', 'IDPrefix', 'user_');
|
||||
$this->config->set('Attr', 'IDPrefixLocal', 'story95_');
|
||||
|
||||
$this->assertDef('alpha', 'user_story95_alpha');
|
||||
$this->assertDef('<asa', false);
|
||||
$this->assertDef('once', 'user_story95_once');
|
||||
$this->assertDef('once', false);
|
||||
|
||||
$this->assertDef('user_story95_alas');
|
||||
$this->assertDef('user_alas', 'user_story95_user_alas'); // !
|
||||
}
|
||||
|
||||
function testLocalPrefixWithoutMainPrefix() {
|
||||
// no effect when IDPrefix isn't set
|
||||
$this->config->set('Attr', 'IDPrefix', '');
|
||||
$this->config->set('Attr', 'IDPrefixLocal', 'story95_');
|
||||
$this->expectError('%Attr.IDPrefixLocal cannot be used unless '.
|
||||
'%Attr.IDPrefix is set');
|
||||
$this->assertDef('amherst');
|
||||
|
||||
}
|
||||
|
||||
// reference functionality is disabled for now
|
||||
function disabled_testIDReference() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_ID(true);
|
||||
|
||||
$this->assertDef('good_id');
|
||||
$this->assertDef('good_id'); // duplicates okay
|
||||
$this->assertDef('<b>', false);
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_ID();
|
||||
|
||||
$this->assertDef('good_id');
|
||||
$this->assertDef('good_id', false); // duplicate now not okay
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_ID(true);
|
||||
|
||||
$this->assertDef('good_id'); // reference still okay
|
||||
|
||||
}
|
||||
|
||||
function testRegexp() {
|
||||
|
||||
$this->config->set('Attr', 'IDBlacklistRegexp', '/^g_/');
|
||||
|
||||
$this->assertDef('good_id');
|
||||
$this->assertDef('g_bad_id', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/PixelsTest.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/Length.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_LengthTest extends HTMLPurifier_AttrDef_HTML_PixelsTest
|
||||
{
|
||||
|
||||
function setup() {
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_Length();
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
||||
// pixel check
|
||||
parent::test();
|
||||
|
||||
// percent check
|
||||
$this->assertDef('25%');
|
||||
|
||||
// Firefox maintains percent, so will we
|
||||
$this->assertDef('0%');
|
||||
|
||||
// 0% <= percent <= 100%
|
||||
$this->assertDef('-15%', '0%');
|
||||
$this->assertDef('120%', '100%');
|
||||
|
||||
// fractional percents, apparently, aren't allowed
|
||||
$this->assertDef('56.5%', '56%');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/LinkTypes.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_LinkTypesTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function testNull() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_LinkTypes('rel');
|
||||
$this->config->set('Attr', 'AllowedRel', array('nofollow', 'foo'));
|
||||
|
||||
$this->assertDef('', false);
|
||||
$this->assertDef('nofollow', true);
|
||||
$this->assertDef('nofollow foo', true);
|
||||
$this->assertDef('nofollow bar', 'nofollow');
|
||||
$this->assertDef('bar', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/LengthTest.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/MultiLength.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_MultiLengthTest extends HTMLPurifier_AttrDef_HTML_LengthTest
|
||||
{
|
||||
|
||||
function setup() {
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_MultiLength();
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
||||
// length check
|
||||
parent::test();
|
||||
|
||||
$this->assertDef('*');
|
||||
$this->assertDef('1*', '*');
|
||||
$this->assertDef('56*');
|
||||
|
||||
$this->assertDef('**', false); // plain old bad
|
||||
|
||||
$this->assertDef('5.4*', '5*'); // no decimals
|
||||
$this->assertDef('-3*', false); // no negatives
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/Nmtokens.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_NmtokensTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function testDefault() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_Nmtokens();
|
||||
|
||||
$this->assertDef('valid');
|
||||
$this->assertDef('a0-_');
|
||||
$this->assertDef('-valid');
|
||||
$this->assertDef('_valid');
|
||||
$this->assertDef('double valid');
|
||||
|
||||
$this->assertDef('0invalid', false);
|
||||
$this->assertDef('-0', false);
|
||||
|
||||
// test conditional replacement
|
||||
$this->assertDef('validassoc 0invalid', 'validassoc');
|
||||
|
||||
// test whitespace leniency
|
||||
$this->assertDef(" double\nvalid\r", 'double valid');
|
||||
|
||||
// test case sensitivity
|
||||
$this->assertDef('VALID');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/Pixels.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_HTML_PixelsTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function setup() {
|
||||
$this->def = new HTMLPurifier_AttrDef_HTML_Pixels();
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
||||
$this->assertDef('1');
|
||||
$this->assertDef('0');
|
||||
|
||||
$this->assertDef('2px', '2'); // rm px suffix
|
||||
|
||||
$this->assertDef('dfs', false); // totally invalid value
|
||||
|
||||
// conceivably we could repair this value, but we won't for now
|
||||
$this->assertDef('9in', false);
|
||||
|
||||
// test trim
|
||||
$this->assertDef(' 45 ', '45');
|
||||
|
||||
// no negatives
|
||||
$this->assertDef('-2', '0');
|
||||
|
||||
// remove empty
|
||||
$this->assertDef('', false);
|
||||
|
||||
// round down
|
||||
$this->assertDef('4.9', '4');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/Integer.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_IntegerTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Integer();
|
||||
|
||||
$this->assertDef('0');
|
||||
$this->assertDef('1');
|
||||
$this->assertDef('-1');
|
||||
$this->assertDef('-10');
|
||||
$this->assertDef('14');
|
||||
$this->assertDef('+24', '24');
|
||||
$this->assertDef(' 14 ', '14');
|
||||
$this->assertDef('-0', '0');
|
||||
|
||||
$this->assertDef('-1.4', false);
|
||||
$this->assertDef('3.4', false);
|
||||
$this->assertDef('asdf', false); // must not return zero
|
||||
$this->assertDef('2in', false); // must not return zero
|
||||
|
||||
}
|
||||
|
||||
function assertRange($negative, $zero, $positive) {
|
||||
$this->assertDef('-100', $negative);
|
||||
$this->assertDef('-1', $negative);
|
||||
$this->assertDef('0', $zero);
|
||||
$this->assertDef('1', $positive);
|
||||
$this->assertDef('42', $positive);
|
||||
}
|
||||
|
||||
function testRange() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Integer(false);
|
||||
$this->assertRange(false, true, true); // non-negative
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Integer(false, false);
|
||||
$this->assertRange(false, false, true); // positive
|
||||
|
||||
|
||||
// fringe cases
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Integer(false, false, false);
|
||||
$this->assertRange(false, false, false); // allow none
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Integer(true, false, false);
|
||||
$this->assertRange(true, false, false); // negative
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Integer(false, true, false);
|
||||
$this->assertRange(false, true, false); // zero
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Integer(true, true, false);
|
||||
$this->assertRange(true, true, false); // non-positive
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/Lang.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_LangTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Lang();
|
||||
|
||||
// basic good uses
|
||||
$this->assertDef('en');
|
||||
$this->assertDef('en-us');
|
||||
|
||||
$this->assertDef(' en ', 'en'); // trim
|
||||
$this->assertDef('EN', 'en'); // case insensitivity
|
||||
|
||||
// (thanks Eugen Pankratz for noticing the typos!)
|
||||
$this->assertDef('En-Us-Edison', 'en-us-edison'); // complex ci
|
||||
|
||||
$this->assertDef('fr en', false); // multiple languages
|
||||
$this->assertDef('%', false); // bad character
|
||||
|
||||
// test overlong language according to syntax
|
||||
$this->assertDef('thisistoolongsoitgetscut', false);
|
||||
|
||||
// primary subtag rules
|
||||
// I'm somewhat hesitant to allow x and i as primary language codes,
|
||||
// because they usually are never used in real life. However,
|
||||
// theoretically speaking, having them alone is permissable, so
|
||||
// I'll be lenient. No XML parser is going to complain anyway.
|
||||
$this->assertDef('x');
|
||||
$this->assertDef('i');
|
||||
// real world use-cases
|
||||
$this->assertDef('x-klingon');
|
||||
$this->assertDef('i-mingo');
|
||||
// because the RFC only defines two and three letter primary codes,
|
||||
// anything with a length of four or greater is invalid, despite
|
||||
// the syntax stipulation of 1 to 8 characters. Because the RFC
|
||||
// specifically states that this reservation is in order to allow
|
||||
// for future versions to expand, the adoption of a new RFC will
|
||||
// require these test cases to be rewritten, even if backwards-
|
||||
// compatibility is largely retained (i.e. this is not forwards
|
||||
// compatible)
|
||||
$this->assertDef('four', false);
|
||||
// for similar reasons, disallow any other one character language
|
||||
$this->assertDef('f', false);
|
||||
|
||||
// second subtag rules
|
||||
// one letter subtags prohibited until revision. This is, however,
|
||||
// less volatile than the restrictions on the primary subtags.
|
||||
// Also note that this test-case tests fix-behavior: chop
|
||||
// off subtags until you get a valid language code.
|
||||
$this->assertDef('en-a', 'en');
|
||||
// however, x is a reserved single-letter subtag that is allowed
|
||||
$this->assertDef('en-x', 'en-x');
|
||||
// 2-8 chars are permitted, but have special meaning that cannot
|
||||
// be checked without maintaining country code lookup tables (for
|
||||
// two characters) or special registration tables (for all above).
|
||||
$this->assertDef('en-uk', true);
|
||||
|
||||
// further subtag rules: only syntactic constraints
|
||||
$this->assertDef('en-us-edison');
|
||||
$this->assertDef('en-us-toolonghaha', 'en-us');
|
||||
$this->assertDef('en-us-a-silly-long-one');
|
||||
|
||||
// rfc 3066 stipulates that if a three letter and a two letter code
|
||||
// are available, the two letter one MUST be used. Without a language
|
||||
// code lookup table, we cannot implement this functionality.
|
||||
|
||||
// although the HTML protocol, technically speaking, allows you to
|
||||
// omit language tags, this implicitly means that the parent element's
|
||||
// language is the one applicable, which, in some cases, is incorrect.
|
||||
// Thus, we allow und, only slightly defying the RFC's SHOULD NOT
|
||||
// designation.
|
||||
$this->assertDef('und');
|
||||
|
||||
// because attributes only allow one language, mul is allowed, complying
|
||||
// with the RFC's SHOULD NOT designation.
|
||||
$this->assertDef('mul');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/Text.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_TextTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_Text();
|
||||
|
||||
$this->assertDef('This is spiffy text!');
|
||||
$this->assertDef(" Casual\tCDATA parse\ncheck. ", 'Casual CDATA parsecheck.');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php';
|
||||
require_once 'HTMLPurifier/AttrDef/URI/EmailHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_URI_Email_SimpleCheckTest
|
||||
extends HTMLPurifier_AttrDef_URI_EmailHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
$this->def = new HTMLPurifier_AttrDef_URI_Email_SimpleCheck();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/URI/Email.php';
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrDef_URI_EmailHarness extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
/**
|
||||
* Tests common email strings that are obviously pass/fail
|
||||
*/
|
||||
function testCore() {
|
||||
$this->assertDef('bob@example.com');
|
||||
$this->assertDef(' bob@example.com ', 'bob@example.com');
|
||||
$this->assertDef('bob.thebuilder@example.net');
|
||||
$this->assertDef('Bob_the_Builder-the-2nd@example.org');
|
||||
$this->assertDef('Bob%20the%20Builder@white-space.test');
|
||||
|
||||
// extended format, with real name
|
||||
//$this->assertDef('Bob%20Builder%20%3Cbobby.bob.bob@it.is.example.com%3E');
|
||||
//$this->assertDef('Bob Builder <bobby.bob.bob@it.is.example.com>');
|
||||
|
||||
// time to fail
|
||||
$this->assertDef('bob', false);
|
||||
$this->assertDef('bob@home@work', false);
|
||||
$this->assertDef('@example.com', false);
|
||||
$this->assertDef('bob@', false);
|
||||
$this->assertDef('', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/URI/Host.php';
|
||||
|
||||
// takes a URI formatted host and validates it
|
||||
|
||||
|
||||
class HTMLPurifier_AttrDef_URI_HostTest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_URI_Host();
|
||||
|
||||
$this->assertDef('[2001:DB8:0:0:8:800:200C:417A]'); // IPv6
|
||||
$this->assertDef('124.15.6.89'); // IPv4
|
||||
$this->assertDef('www.google.com'); // reg-name
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/URI/IPv4.php';
|
||||
|
||||
// IPv4 test case is spliced from Feyd's IPv6 implementation
|
||||
// we ought to disallow non-routable addresses
|
||||
|
||||
class HTMLPurifier_AttrDef_URI_IPv4Test extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_URI_IPv4();
|
||||
|
||||
$this->assertDef('127.0.0.1'); // standard IPv4, loopback, non-routable
|
||||
$this->assertDef('0.0.0.0'); // standard IPv4, unspecified, non-routable
|
||||
$this->assertDef('255.255.255.255'); // standard IPv4
|
||||
|
||||
$this->assertDef('300.0.0.0', false); // standard IPv4, out of range
|
||||
$this->assertDef('124.15.6.89/60', false); // standard IPv4, prefix not allowed
|
||||
|
||||
$this->assertDef('', false); // nothing
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/URI/IPv6.php';
|
||||
|
||||
// test case is from Feyd's IPv6 implementation
|
||||
// we ought to disallow non-routable addresses
|
||||
|
||||
class HTMLPurifier_AttrDef_URI_IPv6Test extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->def = new HTMLPurifier_AttrDef_URI_IPv6();
|
||||
|
||||
$this->assertDef('2001:DB8:0:0:8:800:200C:417A'); // unicast, full
|
||||
$this->assertDef('FF01:0:0:0:0:0:0:101'); // multicast, full
|
||||
$this->assertDef('0:0:0:0:0:0:0:1'); // loopback, full
|
||||
$this->assertDef('0:0:0:0:0:0:0:0'); // unspecified, full
|
||||
$this->assertDef('2001:DB8::8:800:200C:417A'); // unicast, compressed
|
||||
$this->assertDef('FF01::101'); // multicast, compressed
|
||||
|
||||
$this->assertDef('::1'); // loopback, compressed, non-routable
|
||||
$this->assertDef('::'); // unspecified, compressed, non-routable
|
||||
$this->assertDef('0:0:0:0:0:0:13.1.68.3'); // IPv4-compatible IPv6 address, full, deprecated
|
||||
$this->assertDef('0:0:0:0:0:FFFF:129.144.52.38'); // IPv4-mapped IPv6 address, full
|
||||
$this->assertDef('::13.1.68.3'); // IPv4-compatible IPv6 address, compressed, deprecated
|
||||
$this->assertDef('::FFFF:129.144.52.38'); // IPv4-mapped IPv6 address, compressed
|
||||
$this->assertDef('2001:0DB8:0000:CD30:0000:0000:0000:0000/60'); // full, with prefix
|
||||
$this->assertDef('2001:0DB8::CD30:0:0:0:0/60'); // compressed, with prefix
|
||||
$this->assertDef('2001:0DB8:0:CD30::/60'); // compressed, with prefix #2
|
||||
$this->assertDef('::/128'); // compressed, unspecified address type, non-routable
|
||||
$this->assertDef('::1/128'); // compressed, loopback address type, non-routable
|
||||
$this->assertDef('FF00::/8'); // compressed, multicast address type
|
||||
$this->assertDef('FE80::/10'); // compressed, link-local unicast, non-routable
|
||||
$this->assertDef('FEC0::/10'); // compressed, site-local unicast, deprecated
|
||||
|
||||
$this->assertDef('2001:DB8:0:0:8:800:200C:417A:221', false); // unicast, full
|
||||
$this->assertDef('FF01::101::2', false); //multicast, compressed
|
||||
$this->assertDef('', false); // nothing
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||
require_once 'HTMLPurifier/AttrDef/URI.php';
|
||||
require_once 'HTMLPurifier/URIParser.php';
|
||||
|
||||
/**
|
||||
* @todo Aim for complete code coverage with mocks
|
||||
*/
|
||||
class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
$this->def = new HTMLPurifier_AttrDef_URI();
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
function testIntegration() {
|
||||
$this->assertDef('http://www.google.com/');
|
||||
$this->assertDef('http:', '');
|
||||
$this->assertDef('http:/foo', '/foo');
|
||||
$this->assertDef('javascript:bad_stuff();', false);
|
||||
$this->assertDef('ftp://www.example.com/');
|
||||
$this->assertDef('news:rec.alt');
|
||||
$this->assertDef('nntp://news.example.com/324234');
|
||||
$this->assertDef('mailto:bob@example.com');
|
||||
}
|
||||
|
||||
function testIntegrationWithPercentEncoder() {
|
||||
$this->assertDef(
|
||||
'http://www.example.com/%56%fc%GJ%5%FC',
|
||||
'http://www.example.com/V%FC%25GJ%255%FC'
|
||||
);
|
||||
}
|
||||
|
||||
function testEmbeds() {
|
||||
$this->def = new HTMLPurifier_AttrDef_URI(true);
|
||||
$this->assertDef('http://sub.example.com/alas?foo=asd');
|
||||
$this->assertDef('mailto:foo@example.com', false);
|
||||
}
|
||||
|
||||
function testConfigMunge() {
|
||||
$this->config->set('URI', 'Munge', 'http://www.google.com/url?q=%s');
|
||||
$this->assertDef(
|
||||
'http://www.example.com/',
|
||||
'http://www.google.com/url?q=http%3A%2F%2Fwww.example.com%2F'
|
||||
);
|
||||
$this->assertDef('index.html');
|
||||
$this->assertDef('javascript:foobar();', false);
|
||||
}
|
||||
|
||||
function testDefaultSchemeRemovedInBlank() {
|
||||
$this->assertDef('http:', '');
|
||||
}
|
||||
|
||||
function testDefaultSchemeRemovedInRelativeURI() {
|
||||
$this->assertDef('http:/foo/bar', '/foo/bar');
|
||||
}
|
||||
|
||||
function testDefaultSchemeNotRemovedInAbsoluteURI() {
|
||||
$this->assertDef('http://example.com/foo/bar');
|
||||
}
|
||||
|
||||
function testAltSchemeNotRemoved() {
|
||||
$this->assertDef('mailto:this-looks-like-a-path@example.com');
|
||||
}
|
||||
|
||||
function testURIDefinitionValidation() {
|
||||
$parser = new HTMLPurifier_URIParser();
|
||||
$uri = $parser->parse('http://example.com');
|
||||
$this->config->set('URI', 'DefinitionID', 'HTMLPurifier_AttrDef_URITest->testURIDefinitionValidation');
|
||||
$uri_def =& $this->config->getDefinition('URI');
|
||||
// overload with mock
|
||||
generate_mock_once('HTMLPurifier_URIDefinition');
|
||||
$uri_def = new HTMLPurifier_URIDefinitionMock();
|
||||
$uri_def->expectOnce('filter', array($uri, '*', '*'));
|
||||
$uri_def->setReturnValue('filter', true, array($uri, '*', '*'));
|
||||
$uri_def->setup = true;
|
||||
$this->assertDef('http://example.com');
|
||||
}
|
||||
|
||||
/*
|
||||
function test_validate_configWhitelist() {
|
||||
|
||||
$this->config->set('URI', 'HostPolicy', 'DenyAll');
|
||||
$this->config->set('URI', 'HostWhitelist', array(null, 'google.com'));
|
||||
|
||||
$this->assertDef('http://example.com/fo/google.com', false);
|
||||
$this->assertDef('server.txt');
|
||||
$this->assertDef('ftp://www.google.com/?t=a');
|
||||
$this->assertDef('http://google.com.tricky.spamsite.net', false);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
class HTMLPurifier_AttrDefHarness extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
protected $def;
|
||||
protected $context, $config;
|
||||
|
||||
function setUp() {
|
||||
$this->config = HTMLPurifier_Config::createDefault();
|
||||
$this->context = new HTMLPurifier_Context();
|
||||
}
|
||||
|
||||
// cannot be used for accumulator
|
||||
function assertDef($string, $expect = true) {
|
||||
// $expect can be a string or bool
|
||||
$result = $this->def->validate($string, $this->config, $this->context);
|
||||
if ($expect === true) {
|
||||
$this->assertIdentical($string, $result);
|
||||
} else {
|
||||
$this->assertIdentical($expect, $result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef.php';
|
||||
|
||||
Mock::generatePartial(
|
||||
'HTMLPurifier_AttrDef',
|
||||
'HTMLPurifier_AttrDefTestable',
|
||||
array('validate'));
|
||||
|
||||
class HTMLPurifier_AttrDefTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_parseCDATA() {
|
||||
|
||||
$def = new HTMLPurifier_AttrDefTestable();
|
||||
|
||||
$this->assertIdentical('', $def->parseCDATA(''));
|
||||
$this->assertIdentical('', $def->parseCDATA("\t\n\r \t\t"));
|
||||
$this->assertIdentical('foo', $def->parseCDATA("\t\n\r foo\t\t"));
|
||||
$this->assertIdentical('ignorelinefeeds', $def->parseCDATA("ignore\nline\nfeeds"));
|
||||
$this->assertIdentical('translate to space', $def->parseCDATA("translate\rto\tspace"));
|
||||
|
||||
}
|
||||
|
||||
function test_make() {
|
||||
|
||||
$def = new HTMLPurifier_AttrDefTestable();
|
||||
$def2 = $def->make('');
|
||||
$this->assertIdentical($def, $def2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/BdoDir.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrTransform_BdoDirTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_BdoDir();
|
||||
}
|
||||
|
||||
function testAddDefaultDir() {
|
||||
$this->assertResult( array(), array('dir' => 'ltr') );
|
||||
}
|
||||
|
||||
function testPreserveExistingDir() {
|
||||
$this->assertResult( array('dir' => 'rtl') );
|
||||
}
|
||||
|
||||
function testAlternateDefault() {
|
||||
$this->config->set('Attr', 'DefaultTextDir', 'rtl');
|
||||
$this->assertResult(
|
||||
array(),
|
||||
array('dir' => 'rtl')
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/BgColor.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
// we currently rely on the CSS validator to fix any problems.
|
||||
// This means that this transform, strictly speaking, supports
|
||||
// a superset of the functionality.
|
||||
|
||||
class HTMLPurifier_AttrTransform_BgColorTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_BgColor();
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult( array() );
|
||||
}
|
||||
|
||||
function testBasicTransform() {
|
||||
$this->assertResult(
|
||||
array('bgcolor' => '#000000'),
|
||||
array('style' => 'background-color:#000000;')
|
||||
);
|
||||
}
|
||||
|
||||
function testPrependNewCSS() {
|
||||
$this->assertResult(
|
||||
array('bgcolor' => '#000000', 'style' => 'font-weight:bold'),
|
||||
array('style' => 'background-color:#000000;font-weight:bold')
|
||||
);
|
||||
}
|
||||
|
||||
function testLenientTreatmentOfInvalidInput() {
|
||||
// this may change when we natively support the datatype and
|
||||
// validate its contents before forwarding it on
|
||||
$this->assertResult(
|
||||
array('bgcolor' => '#F00'),
|
||||
array('style' => 'background-color:#F00;')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/BoolToCSS.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrTransform_BoolToCSSTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_BoolToCSS('foo', 'bar:3in;');
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult( array() );
|
||||
}
|
||||
|
||||
function testBasicTransform() {
|
||||
$this->assertResult(
|
||||
array('foo' => 'foo'),
|
||||
array('style' => 'bar:3in;')
|
||||
);
|
||||
}
|
||||
|
||||
function testIgnoreValueOfBooleanAttribute() {
|
||||
$this->assertResult(
|
||||
array('foo' => 'no'),
|
||||
array('style' => 'bar:3in;')
|
||||
);
|
||||
}
|
||||
|
||||
function testPrependCSS() {
|
||||
$this->assertResult(
|
||||
array('foo' => 'foo', 'style' => 'background-color:#F00;'),
|
||||
array('style' => 'bar:3in;background-color:#F00;')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/Border.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
|
||||
class HTMLPurifier_AttrTransform_BorderTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_Border();
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult( array() );
|
||||
}
|
||||
|
||||
function testBasicTransform() {
|
||||
$this->assertResult(
|
||||
array('border' => '1'),
|
||||
array('style' => 'border:1px solid;')
|
||||
);
|
||||
}
|
||||
|
||||
function testLenientTreatmentOfInvalidInput() {
|
||||
$this->assertResult(
|
||||
array('border' => '10%'),
|
||||
array('style' => 'border:10%px solid;')
|
||||
);
|
||||
}
|
||||
|
||||
function testPrependNewCSS() {
|
||||
$this->assertResult(
|
||||
array('border' => '23', 'style' => 'font-weight:bold;'),
|
||||
array('style' => 'border:23px solid;font-weight:bold;')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/EnumToCSS.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrTransform_EnumToCSSTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
'left' => 'text-align:left;',
|
||||
'right' => 'text-align:right;'
|
||||
));
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult( array() );
|
||||
}
|
||||
|
||||
function testPreserveArraysWithoutInterestingAttributes() {
|
||||
$this->assertResult( array('style' => 'font-weight:bold;') );
|
||||
}
|
||||
|
||||
function testConvertAlignLeft() {
|
||||
$this->assertResult(
|
||||
array('align' => 'left'),
|
||||
array('style' => 'text-align:left;')
|
||||
);
|
||||
}
|
||||
|
||||
function testConvertAlignRight() {
|
||||
$this->assertResult(
|
||||
array('align' => 'right'),
|
||||
array('style' => 'text-align:right;')
|
||||
);
|
||||
}
|
||||
|
||||
function testRemoveInvalidAlign() {
|
||||
$this->assertResult(
|
||||
array('align' => 'invalid'),
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
function testPrependNewCSS() {
|
||||
$this->assertResult(
|
||||
array('align' => 'left', 'style' => 'font-weight:bold;'),
|
||||
array('style' => 'text-align:left;font-weight:bold;')
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testCaseInsensitive() {
|
||||
$this->obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
'right' => 'text-align:right;'
|
||||
));
|
||||
$this->assertResult(
|
||||
array('align' => 'RIGHT'),
|
||||
array('style' => 'text-align:right;')
|
||||
);
|
||||
}
|
||||
|
||||
function testCaseSensitive() {
|
||||
$this->obj = new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
'right' => 'text-align:right;'
|
||||
), true);
|
||||
$this->assertResult(
|
||||
array('align' => 'RIGHT'),
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/ImgRequired.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrTransform_ImgRequiredTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_ImgRequired();
|
||||
}
|
||||
|
||||
function testAddMissingAttr() {
|
||||
$this->config->set('Core', 'RemoveInvalidImg', false);
|
||||
$this->assertResult(
|
||||
array(),
|
||||
array('src' => '', 'alt' => 'Invalid image')
|
||||
);
|
||||
}
|
||||
|
||||
function testAlternateDefaults() {
|
||||
$this->config->set('Attr', 'DefaultInvalidImage', 'blank.png');
|
||||
$this->config->set('Attr', 'DefaultInvalidImageAlt', 'Pawned!');
|
||||
$this->config->set('Core', 'RemoveInvalidImg', false);
|
||||
$this->assertResult(
|
||||
array(),
|
||||
array('src' => 'blank.png', 'alt' => 'Pawned!')
|
||||
);
|
||||
}
|
||||
|
||||
function testGenerateAlt() {
|
||||
$this->assertResult(
|
||||
array('src' => '/path/to/foobar.png'),
|
||||
array('src' => '/path/to/foobar.png', 'alt' => 'foobar.png')
|
||||
);
|
||||
}
|
||||
|
||||
function testAddDefaultSrc() {
|
||||
$this->config->set('Core', 'RemoveInvalidImg', false);
|
||||
$this->assertResult(
|
||||
array('alt' => 'intrigue'),
|
||||
array('alt' => 'intrigue', 'src' => '')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/ImgSpace.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
|
||||
class HTMLPurifier_AttrTransform_ImgSpaceTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_ImgSpace('vspace');
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult( array() );
|
||||
}
|
||||
|
||||
function testVerticalBasicUsage() {
|
||||
$this->assertResult(
|
||||
array('vspace' => '1'),
|
||||
array('style' => 'margin-top:1px;margin-bottom:1px;')
|
||||
);
|
||||
}
|
||||
|
||||
function testLenientHandlingOfInvalidInput() {
|
||||
$this->assertResult(
|
||||
array('vspace' => '10%'),
|
||||
array('style' => 'margin-top:10%px;margin-bottom:10%px;')
|
||||
);
|
||||
}
|
||||
|
||||
function testPrependNewCSS() {
|
||||
$this->assertResult(
|
||||
array('vspace' => '23', 'style' => 'font-weight:bold;'),
|
||||
array('style' => 'margin-top:23px;margin-bottom:23px;font-weight:bold;')
|
||||
);
|
||||
}
|
||||
|
||||
function testHorizontalBasicUsage() {
|
||||
$this->obj = new HTMLPurifier_AttrTransform_ImgSpace('hspace');
|
||||
$this->assertResult(
|
||||
array('hspace' => '1'),
|
||||
array('style' => 'margin-left:1px;margin-right:1px;')
|
||||
);
|
||||
}
|
||||
|
||||
function testInvalidConstructionParameter() {
|
||||
$this->expectError('ispace is not valid space attribute');
|
||||
$this->obj = new HTMLPurifier_AttrTransform_ImgSpace('ispace');
|
||||
$this->assertResult(
|
||||
array('ispace' => '1'),
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/Token.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/Lang.php';
|
||||
|
||||
class HTMLPurifier_AttrTransform_LangTest
|
||||
extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_Lang();
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult(array());
|
||||
}
|
||||
|
||||
function testCopyLangToXMLLang() {
|
||||
$this->assertResult(
|
||||
array('lang' => 'en'),
|
||||
array('lang' => 'en', 'xml:lang' => 'en')
|
||||
);
|
||||
}
|
||||
|
||||
function testPreserveAttributes() {
|
||||
$this->assertResult(
|
||||
array('src' => 'vert.png', 'lang' => 'fr'),
|
||||
array('src' => 'vert.png', 'lang' => 'fr', 'xml:lang' => 'fr')
|
||||
);
|
||||
}
|
||||
|
||||
function testCopyXMLLangToLang() {
|
||||
$this->assertResult(
|
||||
array('xml:lang' => 'en'),
|
||||
array('xml:lang' => 'en', 'lang' => 'en')
|
||||
);
|
||||
}
|
||||
|
||||
function testXMLLangOverridesLang() {
|
||||
$this->assertResult(
|
||||
array('lang' => 'fr', 'xml:lang' => 'de'),
|
||||
array('lang' => 'de', 'xml:lang' => 'de')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/Length.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrTransform_LengthTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_Length('width');
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult( array() );
|
||||
}
|
||||
|
||||
function testTransformPixel() {
|
||||
$this->assertResult(
|
||||
array('width' => '10'),
|
||||
array('style' => 'width:10px;')
|
||||
);
|
||||
}
|
||||
|
||||
function testTransformPercentage() {
|
||||
$this->assertResult(
|
||||
array('width' => '10%'),
|
||||
array('style' => 'width:10%;')
|
||||
);
|
||||
}
|
||||
|
||||
function testPrependNewCSS() {
|
||||
$this->assertResult(
|
||||
array('width' => '10%', 'style' => 'font-weight:bold'),
|
||||
array('style' => 'width:10%;font-weight:bold')
|
||||
);
|
||||
}
|
||||
|
||||
function testLenientTreatmentOfInvalidInput() {
|
||||
$this->assertResult(
|
||||
array('width' => 'asdf'),
|
||||
array('style' => 'width:asdf;')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/Name.php';
|
||||
require_once 'HTMLPurifier/AttrTransformHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrTransform_NameTest extends HTMLPurifier_AttrTransformHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_AttrTransform_Name();
|
||||
}
|
||||
|
||||
function testEmpty() {
|
||||
$this->assertResult( array() );
|
||||
}
|
||||
|
||||
function testTransformNameToID() {
|
||||
$this->assertResult(
|
||||
array('name' => 'free'),
|
||||
array('id' => 'free')
|
||||
);
|
||||
}
|
||||
|
||||
function testExistingIDOverridesName() {
|
||||
$this->assertResult(
|
||||
array('name' => 'tryit', 'id' => 'tobad'),
|
||||
array('id' => 'tobad')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ComplexHarness.php';
|
||||
|
||||
class HTMLPurifier_AttrTransformHarness extends HTMLPurifier_ComplexHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->func = 'transform';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform.php';
|
||||
|
||||
Mock::generatePartial(
|
||||
'HTMLPurifier_AttrTransform',
|
||||
'HTMLPurifier_AttrTransformTestable',
|
||||
array('transform'));
|
||||
|
||||
class HTMLPurifier_AttrTransformTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_prependCSS() {
|
||||
|
||||
$t = new HTMLPurifier_AttrTransformTestable();
|
||||
|
||||
$attr = array();
|
||||
$t->prependCSS($attr, 'style:new;');
|
||||
$this->assertIdentical(array('style' => 'style:new;'), $attr);
|
||||
|
||||
$attr = array('style' => 'style:original;');
|
||||
$t->prependCSS($attr, 'style:new;');
|
||||
$this->assertIdentical(array('style' => 'style:new;style:original;'), $attr);
|
||||
|
||||
$attr = array('style' => 'style:original;', 'misc' => 'un-related');
|
||||
$t->prependCSS($attr, 'style:new;');
|
||||
$this->assertIdentical(array('style' => 'style:new;style:original;', 'misc' => 'un-related'), $attr);
|
||||
|
||||
}
|
||||
|
||||
function test_confiscateAttr() {
|
||||
|
||||
$t = new HTMLPurifier_AttrTransformTestable();
|
||||
|
||||
$attr = array('flavor' => 'sweet');
|
||||
$this->assertIdentical('sweet', $t->confiscateAttr($attr, 'flavor'));
|
||||
$this->assertIdentical(array(), $attr);
|
||||
|
||||
$attr = array('flavor' => 'sweet');
|
||||
$this->assertIdentical(null, $t->confiscateAttr($attr, 'color'));
|
||||
$this->assertIdentical(array('flavor' => 'sweet'), $attr);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTypes.php';
|
||||
|
||||
class HTMLPurifier_AttrTypesTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_get() {
|
||||
$types = new HTMLPurifier_AttrTypes();
|
||||
|
||||
$this->assertIdentical(
|
||||
$types->get('CDATA'),
|
||||
$types->info['CDATA']
|
||||
);
|
||||
|
||||
$this->expectError('Cannot retrieve undefined attribute type foobar');
|
||||
$types->get('foobar');
|
||||
|
||||
$this->assertIdentical(
|
||||
$types->get('Enum#foo,bar'),
|
||||
new HTMLPurifier_AttrDef_Enum(array('foo', 'bar'))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ErrorsHarness.php';
|
||||
require_once 'HTMLPurifier/AttrValidator.php';
|
||||
|
||||
class HTMLPurifier_AttrValidator_ErrorsTest extends HTMLPurifier_ErrorsHarness
|
||||
{
|
||||
|
||||
function invoke($input) {
|
||||
$validator = new HTMLPurifier_AttrValidator();
|
||||
$validator->validateToken($input, $this->config, $this->context);
|
||||
}
|
||||
|
||||
function testAttributesTransformedGlobalPre() {
|
||||
$this->config->set('HTML', 'DefinitionID',
|
||||
'HTMLPurifier_AttrValidator_ErrorsTest::testAttributesTransformedGlobalPre');
|
||||
$def =& $this->config->getHTMLDefinition(true);
|
||||
generate_mock_once('HTMLPurifier_AttrTransform');
|
||||
$transform = new HTMLPurifier_AttrTransformMock();
|
||||
$input = array('original' => 'value');
|
||||
$output = array('class' => 'value'); // must be valid
|
||||
$transform->setReturnValue('transform', $output, array($input, new AnythingExpectation(), new AnythingExpectation()));
|
||||
$def->info_attr_transform_pre[] = $transform;
|
||||
$this->expectErrorCollection(E_NOTICE, 'AttrValidator: Attributes transformed', $input, $output);
|
||||
$token = new HTMLPurifier_Token_Start('span', $input, 1);
|
||||
$this->invoke($token);
|
||||
}
|
||||
|
||||
function testAttributesTransformedLocalPre() {
|
||||
$this->config->set('HTML', 'TidyLevel', 'heavy');
|
||||
$input = array('align' => 'right');
|
||||
$output = array('style' => 'text-align:right;');
|
||||
$this->expectErrorCollection(E_NOTICE, 'AttrValidator: Attributes transformed', $input, $output);
|
||||
$token = new HTMLPurifier_Token_Start('p', $input, 1);
|
||||
$this->invoke($token);
|
||||
}
|
||||
|
||||
// too lazy to check for global post and global pre
|
||||
|
||||
function testAttributeRemoved() {
|
||||
$this->expectErrorCollection(E_ERROR, 'AttrValidator: Attribute removed');
|
||||
$this->expectContext('CurrentAttr', 'foobar');
|
||||
$token = new HTMLPurifier_Token_Start('p', array('foobar' => 'right'), 1);
|
||||
$this->expectContext('CurrentToken', $token);
|
||||
$this->invoke($token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ChildDefHarness.php';
|
||||
require_once 'HTMLPurifier/ChildDef/Chameleon.php';
|
||||
|
||||
class HTMLPurifier_ChildDef_ChameleonTest extends HTMLPurifier_ChildDefHarness
|
||||
{
|
||||
|
||||
protected $isInline;
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_ChildDef_Chameleon(
|
||||
'b | i', // allowed only when in inline context
|
||||
'b | i | div' // allowed only when in block context
|
||||
);
|
||||
$this->context->register('IsInline', $this->isInline);
|
||||
}
|
||||
|
||||
function testInlineAlwaysAllowed() {
|
||||
$this->isInline = true;
|
||||
$this->assertResult(
|
||||
'<b>Allowed.</b>'
|
||||
);
|
||||
}
|
||||
|
||||
function testBlockNotAllowedInInline() {
|
||||
$this->isInline = true;
|
||||
$this->assertResult(
|
||||
'<div>Not allowed.</div>', ''
|
||||
);
|
||||
}
|
||||
|
||||
function testBlockAllowedInNonInline() {
|
||||
$this->isInline = false;
|
||||
$this->assertResult(
|
||||
'<div>Allowed.</div>'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ChildDefHarness.php';
|
||||
require_once 'HTMLPurifier/ChildDef/Custom.php';
|
||||
|
||||
class HTMLPurifier_ChildDef_CustomTest extends HTMLPurifier_ChildDefHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$this->obj = new HTMLPurifier_ChildDef_Custom('(a,b?,c*,d+,(a,b)*)');
|
||||
|
||||
$this->assertEqual($this->obj->elements, array('a' => true,
|
||||
'b' => true, 'c' => true, 'd' => true));
|
||||
|
||||
$this->assertResult('', false);
|
||||
$this->assertResult('<a /><a />', false);
|
||||
|
||||
$this->assertResult('<a /><b /><c /><d /><a /><b />');
|
||||
$this->assertResult('<a /><d>Dob</d><a /><b>foo</b>'.
|
||||
'<a href="moo" /><b>foo</b>');
|
||||
|
||||
}
|
||||
|
||||
function testNesting() {
|
||||
$this->obj = new HTMLPurifier_ChildDef_Custom('(a,b,(c|d))+');
|
||||
$this->assertEqual($this->obj->elements, array('a' => true,
|
||||
'b' => true, 'c' => true, 'd' => true));
|
||||
$this->assertResult('', false);
|
||||
$this->assertResult('<a /><b /><c /><a /><b /><d />');
|
||||
$this->assertResult('<a /><b /><c /><d />', false);
|
||||
}
|
||||
|
||||
function testNestedEitherOr() {
|
||||
$this->obj = new HTMLPurifier_ChildDef_Custom('b,(a|(c|d))+');
|
||||
$this->assertEqual($this->obj->elements, array('a' => true,
|
||||
'b' => true, 'c' => true, 'd' => true));
|
||||
$this->assertResult('', false);
|
||||
$this->assertResult('<b /><a /><c /><d />');
|
||||
$this->assertResult('<b /><d /><a /><a />');
|
||||
$this->assertResult('<b /><a />');
|
||||
$this->assertResult('<acd />', false);
|
||||
}
|
||||
|
||||
function testNestedQuantifier() {
|
||||
$this->obj = new HTMLPurifier_ChildDef_Custom('(b,c+)*');
|
||||
$this->assertEqual($this->obj->elements, array('b' => true, 'c' => true));
|
||||
$this->assertResult('');
|
||||
$this->assertResult('<b /><c />');
|
||||
$this->assertResult('<b /><c /><c /><c />');
|
||||
$this->assertResult('<b /><c /><b /><c />');
|
||||
$this->assertResult('<b /><c /><b />', false);
|
||||
}
|
||||
|
||||
function testEitherOr() {
|
||||
|
||||
$this->obj = new HTMLPurifier_ChildDef_Custom('a|b');
|
||||
$this->assertEqual($this->obj->elements, array('a' => true, 'b' => true));
|
||||
$this->assertResult('', false);
|
||||
$this->assertResult('<a />');
|
||||
$this->assertResult('<b />');
|
||||
$this->assertResult('<a /><b />', false);
|
||||
|
||||
}
|
||||
|
||||
function testCommafication() {
|
||||
|
||||
$this->obj = new HTMLPurifier_ChildDef_Custom('a,b');
|
||||
$this->assertEqual($this->obj->elements, array('a' => true, 'b' => true));
|
||||
$this->assertResult('<a /><b />');
|
||||
$this->assertResult('<ab />', false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ChildDefHarness.php';
|
||||
require_once 'HTMLPurifier/ChildDef/Optional.php';
|
||||
|
||||
class HTMLPurifier_ChildDef_OptionalTest extends HTMLPurifier_ChildDefHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_ChildDef_Optional('b | i');
|
||||
}
|
||||
|
||||
function testBasicUsage() {
|
||||
$this->assertResult('<b>Bold text</b><img />', '<b>Bold text</b>');
|
||||
}
|
||||
|
||||
function testRemoveForbiddenText() {
|
||||
$this->assertResult('Not allowed text', '');
|
||||
}
|
||||
|
||||
function testEmpty() {
|
||||
$this->assertResult('');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ChildDefHarness.php';
|
||||
require_once 'HTMLPurifier/ChildDef/Required.php';
|
||||
|
||||
class HTMLPurifier_ChildDef_RequiredTest extends HTMLPurifier_ChildDefHarness
|
||||
{
|
||||
|
||||
function testPrepareString() {
|
||||
$def = new HTMLPurifier_ChildDef_Required('foobar | bang |gizmo');
|
||||
$this->assertIdentical($def->elements,
|
||||
array(
|
||||
'foobar' => true
|
||||
,'bang' => true
|
||||
,'gizmo' => true
|
||||
));
|
||||
}
|
||||
|
||||
function testPrepareArray() {
|
||||
$def = new HTMLPurifier_ChildDef_Required(array('href', 'src'));
|
||||
$this->assertIdentical($def->elements,
|
||||
array(
|
||||
'href' => true
|
||||
,'src' => true
|
||||
));
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_ChildDef_Required('dt | dd');
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult('', false);
|
||||
}
|
||||
|
||||
function testRemoveIllegalTagsAndElements() {
|
||||
$this->assertResult(
|
||||
'<dt>Term</dt>Text in an illegal location'.
|
||||
'<dd>Definition</dd><b>Illegal tag</b>',
|
||||
'<dt>Term</dt><dd>Definition</dd>');
|
||||
$this->assertResult('How do you do!', false);
|
||||
}
|
||||
|
||||
function testIgnoreWhitespace() {
|
||||
// whitespace shouldn't trigger it
|
||||
$this->assertResult("\n<dd>Definition</dd> ");
|
||||
}
|
||||
|
||||
function testPreserveWhitespaceAfterRemoval() {
|
||||
$this->assertResult(
|
||||
'<dd>Definition</dd> <b></b> ',
|
||||
'<dd>Definition</dd> '
|
||||
);
|
||||
}
|
||||
|
||||
function testDeleteNodeIfOnlyWhitespace() {
|
||||
$this->assertResult("\t ", false);
|
||||
}
|
||||
|
||||
function testPCDATAAllowed() {
|
||||
$this->obj = new HTMLPurifier_ChildDef_Required('#PCDATA | b');
|
||||
$this->assertResult('Out <b>Bold text</b><img />', 'Out <b>Bold text</b>');
|
||||
}
|
||||
|
||||
function testPCDATAAllowedWithEscaping() {
|
||||
$this->obj = new HTMLPurifier_ChildDef_Required('#PCDATA | b');
|
||||
$this->config->set('Core', 'EscapeInvalidChildren', true);
|
||||
$this->assertResult(
|
||||
'Out <b>Bold text</b><img />',
|
||||
'Out <b>Bold text</b><img />'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ChildDefHarness.php';
|
||||
require_once 'HTMLPurifier/ChildDef/StrictBlockquote.php';
|
||||
|
||||
class HTMLPurifier_ChildDef_StrictBlockquoteTest
|
||||
extends HTMLPurifier_ChildDefHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_ChildDef_StrictBlockquote('div | p');
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult('');
|
||||
}
|
||||
|
||||
function testPreserveValidP() {
|
||||
$this->assertResult('<p>Valid</p>');
|
||||
}
|
||||
|
||||
function testPreserveValidDiv() {
|
||||
$this->assertResult('<div>Still valid</div>');
|
||||
}
|
||||
|
||||
function testWrapTextWithP() {
|
||||
$this->assertResult('Needs wrap', '<p>Needs wrap</p>');
|
||||
}
|
||||
|
||||
function testNoWrapForWhitespaceOrValidElements() {
|
||||
$this->assertResult('<p>Do not wrap</p> <p>Whitespace</p>');
|
||||
}
|
||||
|
||||
function testWrapTextNextToValidElements() {
|
||||
$this->assertResult(
|
||||
'Wrap'. '<p>Do not wrap</p>',
|
||||
'<p>Wrap</p><p>Do not wrap</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testWrapInlineElements() {
|
||||
$this->assertResult(
|
||||
'<p>Do not</p>'.'<b>Wrap</b>',
|
||||
'<p>Do not</p><p><b>Wrap</b></p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testWrapAndRemoveInvalidTags() {
|
||||
$this->assertResult(
|
||||
'<li>Not allowed</li>Paragraph.<p>Hmm.</p>',
|
||||
'<p>Not allowedParagraph.</p><p>Hmm.</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testWrapComplicatedSring() {
|
||||
$this->assertResult(
|
||||
$var = 'He said<br />perhaps<br />we should <b>nuke</b> them.',
|
||||
"<p>$var</p>"
|
||||
);
|
||||
}
|
||||
|
||||
function testWrapAndRemoveInvalidTagsComplex() {
|
||||
$this->assertResult(
|
||||
'<foo>Bar</foo><bas /><b>People</b>Conniving.'. '<p>Fools!</p>',
|
||||
'<p>Bar'. '<b>People</b>Conniving.</p><p>Fools!</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testAlternateWrapper() {
|
||||
$this->config->set('HTML', 'BlockWrapper', 'div');
|
||||
$this->assertResult('Needs wrap', '<div>Needs wrap</div>');
|
||||
|
||||
}
|
||||
|
||||
function testError() {
|
||||
// $this->expectError('Cannot use non-block element as block wrapper');
|
||||
$this->obj = new HTMLPurifier_ChildDef_StrictBlockquote('div | p');
|
||||
$this->config->set('HTML', 'BlockWrapper', 'dav');
|
||||
$this->assertResult('Needs wrap', '<p>Needs wrap</p>');
|
||||
$this->swallowErrors();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ChildDefHarness.php';
|
||||
require_once 'HTMLPurifier/ChildDef/Table.php';
|
||||
|
||||
// we're using empty tags to compact the tests: under real circumstances
|
||||
// there would be contents in them
|
||||
|
||||
class HTMLPurifier_ChildDef_TableTest extends HTMLPurifier_ChildDefHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = new HTMLPurifier_ChildDef_Table();
|
||||
}
|
||||
|
||||
function testEmptyInput() {
|
||||
$this->assertResult('', false);
|
||||
}
|
||||
|
||||
function testSingleRow() {
|
||||
$this->assertResult('<tr />');
|
||||
}
|
||||
|
||||
function testComplexContents() {
|
||||
$this->assertResult('<caption /><col /><thead /><tfoot /><tbody>'.
|
||||
'<tr><td>asdf</td></tr></tbody>');
|
||||
$this->assertResult('<col /><col /><col /><tr />');
|
||||
}
|
||||
|
||||
function testReorderContents() {
|
||||
$this->assertResult(
|
||||
'<col /><colgroup /><tbody /><tfoot /><thead /><tr>1</tr><caption /><tr />',
|
||||
'<caption /><col /><colgroup /><thead /><tfoot /><tbody /><tr>1</tr><tr />');
|
||||
}
|
||||
|
||||
function testDuplicateProcessing() {
|
||||
$this->assertResult(
|
||||
'<caption>1</caption><caption /><tbody /><tbody /><tfoot>1</tfoot><tfoot />',
|
||||
'<caption>1</caption><tfoot>1</tfoot><tbody /><tbody /><tbody />'
|
||||
);
|
||||
}
|
||||
|
||||
function testRemoveText() {
|
||||
$this->assertResult('foo', false);
|
||||
}
|
||||
|
||||
function testStickyWhitespaceOnTr() {
|
||||
$this->config->set('Output', 'Newline', "\n");
|
||||
$this->assertResult("\n <tr />\n <tr />\n ");
|
||||
}
|
||||
|
||||
function testStickyWhitespaceOnTSection() {
|
||||
$this->config->set('Output', 'Newline', "\n");
|
||||
$this->assertResult(
|
||||
"\n\t<tbody />\n\t\t<tfoot />\n\t\t\t",
|
||||
"\n\t\t<tfoot />\n\t<tbody />\n\t\t\t"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ComplexHarness.php';
|
||||
require_once 'HTMLPurifier/ChildDef.php';
|
||||
|
||||
class HTMLPurifier_ChildDefHarness extends HTMLPurifier_ComplexHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->obj = null;
|
||||
$this->func = 'validateChildren';
|
||||
$this->to_tokens = true;
|
||||
$this->to_html = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
||||
|
||||
/**
|
||||
* General-purpose test-harness that makes testing functions that require
|
||||
* configuration and context objects easier when those two parameters are
|
||||
* meaningless. See HTMLPurifier_ChildDefTest for a good example of usage.
|
||||
*/
|
||||
class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
/**
|
||||
* Instance of the object that will execute the method
|
||||
*/
|
||||
protected $obj;
|
||||
|
||||
/**
|
||||
* Name of the function to be executed
|
||||
*/
|
||||
protected $func;
|
||||
|
||||
/**
|
||||
* Whether or not the method deals in tokens. If set to true, assertResult()
|
||||
* will transparently convert HTML to and back from tokens.
|
||||
*/
|
||||
protected $to_tokens = false;
|
||||
|
||||
/**
|
||||
* Whether or not to convert tokens back into HTML before performing
|
||||
* equality check, has no effect on bools.
|
||||
*/
|
||||
protected $to_html = false;
|
||||
|
||||
/**
|
||||
* Instance of an HTMLPurifier_Lexer implementation.
|
||||
*/
|
||||
protected $lexer;
|
||||
|
||||
/**
|
||||
* Instance of HTMLPurifier_Generator
|
||||
*/
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
function HTMLPurifier_ComplexHarness() {
|
||||
$this->lexer = new HTMLPurifier_Lexer_DirectLex();
|
||||
$this->generator = new HTMLPurifier_Generator();
|
||||
parent::HTMLPurifier_Harness();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a specific result from a one parameter + config/context function
|
||||
* @param $input Input parameter
|
||||
* @param $expect Expectation
|
||||
* @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) {
|
||||
|
||||
if ($this->to_tokens && is_string($input)) {
|
||||
// $func may cause $input to change, so "clone" another copy
|
||||
// to sacrifice
|
||||
$input = $this->tokenize($temp = $input);
|
||||
$input_c = $this->tokenize($temp);
|
||||
} else {
|
||||
$input_c = $input;
|
||||
}
|
||||
|
||||
// call the function
|
||||
$func = $this->func;
|
||||
$result = $this->obj->$func($input_c, $this->config, $this->context);
|
||||
|
||||
// test a bool result
|
||||
if (is_bool($result)) {
|
||||
$this->assertIdentical($expect, $result);
|
||||
return;
|
||||
} elseif (is_bool($expect)) {
|
||||
$expect = $input;
|
||||
}
|
||||
|
||||
if ($this->to_html) {
|
||||
$result = $this->generate($result);
|
||||
if (is_array($expect)) {
|
||||
$expect = $this->generate($expect);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertIdentical($expect, $result);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenize HTML into tokens, uses member variables for common variables
|
||||
*/
|
||||
function tokenize($html) {
|
||||
return $this->lexer->tokenizeHTML($html, $this->config, $this->context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate textual HTML from tokens
|
||||
*/
|
||||
function generate($tokens) {
|
||||
return $this->generator->generateFromTokens($tokens, $this->config, $this->context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ConfigSchema.php';
|
||||
|
||||
if (!class_exists('CS')) {
|
||||
class CS extends HTMLPurifier_ConfigSchema {}
|
||||
}
|
||||
|
||||
class HTMLPurifier_ConfigSchemaTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
/**
|
||||
* Munged name of current file.
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* Copy of the real ConfigSchema to revert to.
|
||||
*/
|
||||
protected $old_copy;
|
||||
|
||||
/**
|
||||
* Copy of dummy ConfigSchema for testing purposes.
|
||||
*/
|
||||
protected $our_copy;
|
||||
|
||||
function setUp() {
|
||||
// yes, I know this is slightly convoluted, but that's the price
|
||||
// you pay for using Singletons. Good thing we can overload it.
|
||||
|
||||
// first, let's get a clean copy to do tests
|
||||
$our_copy = new HTMLPurifier_ConfigSchema();
|
||||
// get the old copy
|
||||
$this->old_copy = HTMLPurifier_ConfigSchema::instance();
|
||||
// put in our copy, and reassign to the REAL reference
|
||||
$this->our_copy =& HTMLPurifier_ConfigSchema::instance($our_copy);
|
||||
|
||||
$this->file = $this->our_copy->mungeFilename(__FILE__);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
// testing is done, restore the old copy
|
||||
HTMLPurifier_ConfigSchema::instance($this->old_copy);
|
||||
tally_errors($this);
|
||||
}
|
||||
|
||||
function test_defineNamespace() {
|
||||
CS::defineNamespace('http', $d = 'This is an internet protocol.');
|
||||
|
||||
$this->assertIdentical($this->our_copy->info_namespace, array(
|
||||
'http' => new HTMLPurifier_ConfigDef_Namespace($d)
|
||||
));
|
||||
|
||||
$this->expectError('Cannot redefine namespace');
|
||||
CS::defineNamespace('http', 'It is used to serve webpages.');
|
||||
|
||||
$this->expectError('Namespace name must be alphanumeric');
|
||||
CS::defineNamespace('ssh+http', 'This http is tunneled through SSH.');
|
||||
|
||||
$this->expectError('Description must be non-empty');
|
||||
CS::defineNamespace('ftp', null);
|
||||
}
|
||||
|
||||
function test_define() {
|
||||
CS::defineNamespace('Car', 'Automobiles, those gas-guzzlers!');
|
||||
|
||||
CS::define('Car', 'Seats', 5, 'int', $d = 'Standard issue.'); $l = __LINE__;
|
||||
|
||||
$this->assertIdentical($this->our_copy->defaults['Car']['Seats'], 5);
|
||||
$this->assertIdentical($this->our_copy->info['Car']['Seats'],
|
||||
new HTMLPurifier_ConfigDef_Directive('int',
|
||||
array($this->file => array($l => $d))
|
||||
)
|
||||
);
|
||||
|
||||
CS::define('Car', 'Age', null, 'int/null', $d = 'Not always known.'); $l = __LINE__;
|
||||
|
||||
$this->assertIdentical($this->our_copy->defaults['Car']['Age'], null);
|
||||
$this->assertIdentical($this->our_copy->info['Car']['Age'],
|
||||
new HTMLPurifier_ConfigDef_Directive('int',
|
||||
array($this->file => array($l => $d)), true
|
||||
)
|
||||
);
|
||||
|
||||
$this->expectError('Cannot define directive for undefined namespace');
|
||||
CS::define('Train', 'Cars', 10, 'int', 'Including the caboose.');
|
||||
|
||||
$this->expectError('Directive name must be alphanumeric');
|
||||
CS::define('Car', 'Is it shiny?', true, 'bool', 'Indicates regular waxing.');
|
||||
|
||||
$this->expectError('Invalid type for configuration directive');
|
||||
CS::define('Car', 'Efficiency', 50, 'mpg', 'The higher the better.');
|
||||
|
||||
$this->expectError('Default value does not match directive type');
|
||||
CS::define('Car', 'Producer', 'Ford', 'int', 'ID of the company that made the car.');
|
||||
|
||||
$this->expectError('Description must be non-empty');
|
||||
CS::define('Car', 'ComplexAttribute', 'lawyers', 'istring', null);
|
||||
}
|
||||
|
||||
function testRedefinition_define() {
|
||||
CS::defineNamespace('Cat', 'Belongs to Schrodinger.');
|
||||
|
||||
CS::define('Cat', 'Dead', false, 'bool', $d1 = 'Well, is it?'); $l1 = __LINE__;
|
||||
CS::define('Cat', 'Dead', false, 'bool', $d2 = 'It is difficult to say.'); $l2 = __LINE__;
|
||||
|
||||
$this->assertIdentical($this->our_copy->defaults['Cat']['Dead'], false);
|
||||
$this->assertIdentical($this->our_copy->info['Cat']['Dead'],
|
||||
new HTMLPurifier_ConfigDef_Directive('bool',
|
||||
array($this->file => array($l1 => $d1, $l2 => $d2))
|
||||
)
|
||||
);
|
||||
|
||||
$this->expectError('Inconsistent default or type, cannot redefine');
|
||||
CS::define('Cat', 'Dead', true, 'bool', 'Quantum mechanics does not know.');
|
||||
|
||||
$this->expectError('Inconsistent default or type, cannot redefine');
|
||||
CS::define('Cat', 'Dead', 'maybe', 'string', 'Perhaps if we look we will know.');
|
||||
}
|
||||
|
||||
function test_defineAllowedValues() {
|
||||
CS::defineNamespace('QuantumNumber', 'D');
|
||||
CS::define('QuantumNumber', 'Spin', 0.5, 'float',
|
||||
'Spin of particle. Fourth quantum number, represented by s.');
|
||||
CS::define('QuantumNumber', 'Current', 's', 'string',
|
||||
'Currently selected quantum number.');
|
||||
CS::define('QuantumNumber', 'Difficulty', null, 'string/null', $d = 'How hard are the problems?'); $l = __LINE__;
|
||||
|
||||
CS::defineAllowedValues( // okay, since default is null
|
||||
'QuantumNumber', 'Difficulty', array('easy', 'medium', 'hard')
|
||||
);
|
||||
|
||||
$this->assertIdentical($this->our_copy->defaults['QuantumNumber']['Difficulty'], null);
|
||||
$this->assertIdentical($this->our_copy->info['QuantumNumber']['Difficulty'],
|
||||
new HTMLPurifier_ConfigDef_Directive(
|
||||
'string',
|
||||
array($this->file => array($l => $d)),
|
||||
true,
|
||||
array(
|
||||
'easy' => true,
|
||||
'medium' => true,
|
||||
'hard' => true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->expectError('Cannot define allowed values for undefined directive');
|
||||
CS::defineAllowedValues(
|
||||
'SpaceTime', 'Symmetry', array('time', 'spatial', 'projective')
|
||||
);
|
||||
|
||||
$this->expectError('Cannot define allowed values for directive whose type is not string');
|
||||
CS::defineAllowedValues(
|
||||
'QuantumNumber', 'Spin', array(0.5, -0.5)
|
||||
);
|
||||
|
||||
$this->expectError('Default value must be in allowed range of variables');
|
||||
CS::defineAllowedValues(
|
||||
'QuantumNumber', 'Current', array('n', 'l', 'm') // forgot s!
|
||||
);
|
||||
}
|
||||
|
||||
function test_defineValueAliases() {
|
||||
CS::defineNamespace('Abbrev', 'Stuff on abbreviations.');
|
||||
CS::define('Abbrev', 'HTH', 'Happy to Help', 'string', $d = 'Three-letters'); $l = __LINE__;
|
||||
CS::defineAllowedValues(
|
||||
'Abbrev', 'HTH', array(
|
||||
'Happy to Help',
|
||||
'Hope that Helps',
|
||||
'HAIL THE HAND!'
|
||||
)
|
||||
);
|
||||
CS::defineValueAliases(
|
||||
'Abbrev', 'HTH', array(
|
||||
'happy' => 'Happy to Help',
|
||||
'hope' => 'Hope that Helps'
|
||||
)
|
||||
);
|
||||
CS::defineValueAliases( // delayed addition
|
||||
'Abbrev', 'HTH', array(
|
||||
'hail' => 'HAIL THE HAND!'
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertIdentical($this->our_copy->defaults['Abbrev']['HTH'], 'Happy to Help');
|
||||
$this->assertIdentical($this->our_copy->info['Abbrev']['HTH'],
|
||||
new HTMLPurifier_ConfigDef_Directive(
|
||||
'string',
|
||||
array($this->file => array($l => $d)),
|
||||
false,
|
||||
array(
|
||||
'Happy to Help' => true,
|
||||
'Hope that Helps' => true,
|
||||
'HAIL THE HAND!' => true
|
||||
),
|
||||
array(
|
||||
'happy' => 'Happy to Help',
|
||||
'hope' => 'Hope that Helps',
|
||||
'hail' => 'HAIL THE HAND!'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->expectError('Cannot define alias to value that is not allowed');
|
||||
CS::defineValueAliases(
|
||||
'Abbrev', 'HTH', array(
|
||||
'head' => 'Head to Head'
|
||||
)
|
||||
);
|
||||
|
||||
$this->expectError('Cannot define alias over allowed value');
|
||||
CS::defineValueAliases(
|
||||
'Abbrev', 'HTH', array(
|
||||
'Hope that Helps' => 'Happy to Help'
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testAlias() {
|
||||
CS::defineNamespace('Home', 'Sweet home.');
|
||||
CS::define('Home', 'Rug', 3, 'int', 'ID.');
|
||||
CS::defineAlias('Home', 'Carpet', 'Home', 'Rug');
|
||||
|
||||
$this->assertTrue(!isset($this->our_copy->defaults['Home']['Carpet']));
|
||||
$this->assertIdentical($this->our_copy->info['Home']['Carpet'],
|
||||
new HTMLPurifier_ConfigDef_DirectiveAlias('Home', 'Rug')
|
||||
);
|
||||
|
||||
$this->expectError('Cannot define directive alias in undefined namespace');
|
||||
CS::defineAlias('Store', 'Rug', 'Home', 'Rug');
|
||||
|
||||
$this->expectError('Directive name must be alphanumeric');
|
||||
CS::defineAlias('Home', 'R.g', 'Home', 'Rug');
|
||||
|
||||
CS::define('Home', 'Rugger', 'Bob Max', 'string', 'Name of.');
|
||||
$this->expectError('Cannot define alias over directive');
|
||||
CS::defineAlias('Home', 'Rugger', 'Home', 'Rug');
|
||||
|
||||
$this->expectError('Cannot define alias to undefined directive');
|
||||
CS::defineAlias('Home', 'Rug2', 'Home', 'Rugavan');
|
||||
|
||||
$this->expectError('Cannot define alias to alias');
|
||||
CS::defineAlias('Home', 'Rug2', 'Home', 'Carpet');
|
||||
}
|
||||
|
||||
function assertValid($var, $type, $ret = null) {
|
||||
$ret = ($ret === null) ? $var : $ret;
|
||||
$this->assertIdentical($this->our_copy->validate($var, $type), $ret);
|
||||
}
|
||||
|
||||
function assertInvalid($var, $type) {
|
||||
$this->assertTrue(
|
||||
$this->our_copy->isError(
|
||||
$this->our_copy->validate($var, $type)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function testValidate() {
|
||||
|
||||
$this->assertValid('foobar', 'string');
|
||||
$this->assertValid('foobar', 'text'); // aliases, lstring = long string
|
||||
$this->assertValid('FOOBAR', 'istring', 'foobar');
|
||||
$this->assertValid('FOOBAR', 'itext', 'foobar');
|
||||
|
||||
$this->assertValid(34, 'int');
|
||||
|
||||
$this->assertValid(3.34, 'float');
|
||||
|
||||
$this->assertValid(false, 'bool');
|
||||
$this->assertValid(0, 'bool', false);
|
||||
$this->assertValid(1, 'bool', true);
|
||||
$this->assertValid('true', 'bool', true);
|
||||
$this->assertValid('false', 'bool', false);
|
||||
$this->assertValid('1', 'bool', true);
|
||||
$this->assertInvalid(34, 'bool');
|
||||
$this->assertInvalid(null, 'bool');
|
||||
|
||||
$this->assertValid(array('1', '2', '3'), 'list');
|
||||
$this->assertValid('foo,bar, cow', 'list', array('foo', 'bar', 'cow'));
|
||||
$this->assertValid('', 'list', array());
|
||||
$this->assertValid("foo\nbar", 'list', array('foo', 'bar'));
|
||||
$this->assertValid("foo\nbar,baz", 'list', array('foo', 'bar', 'baz'));
|
||||
|
||||
$this->assertValid(array('1' => true, '2' => true), 'lookup');
|
||||
$this->assertValid(array('1', '2'), 'lookup', array('1' => true, '2' => true));
|
||||
$this->assertValid('foo,bar', 'lookup', array('foo' => true, 'bar' => true));
|
||||
$this->assertValid("foo\nbar", 'lookup', array('foo' => true, 'bar' => true));
|
||||
$this->assertValid("foo\nbar,baz", 'lookup', array('foo' => true, 'bar' => true, 'baz' => true));
|
||||
$this->assertValid('', 'lookup', array());
|
||||
|
||||
$this->assertValid(array('foo' => 'bar'), 'hash');
|
||||
$this->assertValid(array(1 => 'moo'), 'hash');
|
||||
$this->assertInvalid(array(0 => 'moo'), 'hash');
|
||||
$this->assertValid('', 'hash', array());
|
||||
$this->assertValid('foo:bar,too:two', 'hash', array('foo' => 'bar', 'too' => 'two'));
|
||||
$this->assertValid("foo:bar\ntoo:two,three:free", 'hash', array('foo' => 'bar', 'too' => 'two', 'three' => 'free'));
|
||||
$this->assertValid('foo:bar,too', 'hash', array('foo' => 'bar'));
|
||||
$this->assertValid('foo:bar,', 'hash', array('foo' => 'bar'));
|
||||
$this->assertValid('foo:bar:baz', 'hash', array('foo' => 'bar:baz'));
|
||||
|
||||
$this->assertValid(23, 'mixed');
|
||||
|
||||
}
|
||||
|
||||
function testValidate_null() {
|
||||
|
||||
$this->assertTrue(
|
||||
$this->our_copy->isError(
|
||||
$this->our_copy->validate(null, 'string', false)
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertFalse(
|
||||
$this->our_copy->isError(
|
||||
$this->our_copy->validate(null, 'string', true)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function assertMungeFilename($oldname, $newname) {
|
||||
$this->assertIdentical(
|
||||
$this->our_copy->mungeFilename($oldname),
|
||||
$newname
|
||||
);
|
||||
}
|
||||
|
||||
function testMungeFilename() {
|
||||
|
||||
$this->assertMungeFilename(
|
||||
'C:\\php\\My Libraries\\htmlpurifier\\library\\HTMLPurifier\\AttrDef.php',
|
||||
'HTMLPurifier/AttrDef.php'
|
||||
);
|
||||
|
||||
$this->assertMungeFilename(
|
||||
'C:\\php\\My Libraries\\htmlpurifier\\library\\HTMLPurifier.php',
|
||||
'HTMLPurifier.php'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[Cake]
|
||||
Sprinkles = 42
|
||||
@@ -0,0 +1,2 @@
|
||||
[Poem]
|
||||
Meter = alexandrine
|
||||
@@ -0,0 +1,4 @@
|
||||
[Shortcut]
|
||||
Copy = q
|
||||
Cut = t
|
||||
Paste = p
|
||||
@@ -0,0 +1,460 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/Config.php';
|
||||
|
||||
if (!class_exists('CS')) {
|
||||
class CS extends HTMLPurifier_ConfigSchema {}
|
||||
}
|
||||
|
||||
class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
protected $our_copy, $old_copy;
|
||||
|
||||
function setUp() {
|
||||
// set up a dummy schema object for testing
|
||||
$our_copy = new HTMLPurifier_ConfigSchema();
|
||||
$this->old_copy = HTMLPurifier_ConfigSchema::instance();
|
||||
$this->our_copy =& HTMLPurifier_ConfigSchema::instance($our_copy);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
HTMLPurifier_ConfigSchema::instance($this->old_copy);
|
||||
tally_errors($this);
|
||||
}
|
||||
|
||||
// test functionality based on ConfigSchema
|
||||
|
||||
function testNormal() {
|
||||
CS::defineNamespace('Element', 'Chemical substances that cannot be further decomposed');
|
||||
|
||||
CS::define('Element', 'Abbr', 'H', 'string', 'Abbreviation of element name.');
|
||||
CS::define('Element', 'Name', 'hydrogen', 'istring', 'Full name of atoms.');
|
||||
CS::define('Element', 'Number', 1, 'int', 'Atomic number, is identity.');
|
||||
CS::define('Element', 'Mass', 1.00794, 'float', 'Atomic mass.');
|
||||
CS::define('Element', 'Radioactive', false, 'bool', 'Does it have rapid decay?');
|
||||
CS::define('Element', 'Isotopes', array(1 => true, 2 => true, 3 => true), 'lookup',
|
||||
'What numbers of neutrons for this element have been observed?');
|
||||
CS::define('Element', 'Traits', array('nonmetallic', 'odorless', 'flammable'), 'list',
|
||||
'What are general properties of the element?');
|
||||
CS::define('Element', 'IsotopeNames', array(1 => 'protium', 2 => 'deuterium', 3 => 'tritium'), 'hash',
|
||||
'Lookup hash of neutron counts to formal names.');
|
||||
CS::define('Element', 'Object', new stdClass(), 'mixed', 'Model representation.');
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->autoFinalize = false;
|
||||
|
||||
// test default value retrieval
|
||||
$this->assertIdentical($config->get('Element', 'Abbr'), 'H');
|
||||
$this->assertIdentical($config->get('Element', 'Name'), 'hydrogen');
|
||||
$this->assertIdentical($config->get('Element', 'Number'), 1);
|
||||
$this->assertIdentical($config->get('Element', 'Mass'), 1.00794);
|
||||
$this->assertIdentical($config->get('Element', 'Radioactive'), false);
|
||||
$this->assertIdentical($config->get('Element', 'Isotopes'), array(1 => true, 2 => true, 3 => true));
|
||||
$this->assertIdentical($config->get('Element', 'Traits'), array('nonmetallic', 'odorless', 'flammable'));
|
||||
$this->assertIdentical($config->get('Element', 'IsotopeNames'), array(1 => 'protium', 2 => 'deuterium', 3 => 'tritium'));
|
||||
$this->assertIdentical($config->get('Element', 'Object'), new stdClass());
|
||||
|
||||
// test setting values
|
||||
$config->set('Element', 'Abbr', 'Pu');
|
||||
$config->set('Element', 'Name', 'PLUTONIUM'); // test decaps
|
||||
$config->set('Element', 'Number', '94'); // test parsing
|
||||
$config->set('Element', 'Mass', '244.'); // test parsing
|
||||
$config->set('Element', 'Radioactive', true);
|
||||
$config->set('Element', 'Isotopes', array(238, 239)); // test inversion
|
||||
$config->set('Element', 'Traits', 'nuclear, heavy, actinide'); // test parsing
|
||||
$config->set('Element', 'IsotopeNames', array(238 => 'Plutonium-238', 239 => 'Plutonium-239'));
|
||||
$config->set('Element', 'Object', false); // unmodeled
|
||||
|
||||
$this->expectError('Cannot set undefined directive Element.Metal to value');
|
||||
$config->set('Element', 'Metal', true);
|
||||
|
||||
$this->expectError('Value for Element.Radioactive is of invalid type, should be bool');
|
||||
$config->set('Element', 'Radioactive', 'very');
|
||||
|
||||
// test value retrieval
|
||||
$this->assertIdentical($config->get('Element', 'Abbr'), 'Pu');
|
||||
$this->assertIdentical($config->get('Element', 'Name'), 'plutonium');
|
||||
$this->assertIdentical($config->get('Element', 'Number'), 94);
|
||||
$this->assertIdentical($config->get('Element', 'Mass'), 244.);
|
||||
$this->assertIdentical($config->get('Element', 'Radioactive'), true);
|
||||
$this->assertIdentical($config->get('Element', 'Isotopes'), array(238 => true, 239 => true));
|
||||
$this->assertIdentical($config->get('Element', 'Traits'), array('nuclear', 'heavy', 'actinide'));
|
||||
$this->assertIdentical($config->get('Element', 'IsotopeNames'), array(238 => 'Plutonium-238', 239 => 'Plutonium-239'));
|
||||
$this->assertIdentical($config->get('Element', 'Object'), false);
|
||||
|
||||
$this->expectError('Cannot retrieve value of undefined directive Element.Metal');
|
||||
$config->get('Element', 'Metal');
|
||||
|
||||
}
|
||||
|
||||
function testEnumerated() {
|
||||
|
||||
CS::defineNamespace('Instrument', 'Of the musical type.');
|
||||
|
||||
// case sensitive
|
||||
CS::define('Instrument', 'Manufacturer', 'Yamaha', 'string', 'Who made it?');
|
||||
CS::defineAllowedValues('Instrument', 'Manufacturer', array(
|
||||
'Yamaha', 'Conn-Selmer', 'Vandoren', 'Laubin', 'Buffet', 'other'));
|
||||
CS::defineValueAliases('Instrument', 'Manufacturer', array(
|
||||
'Selmer' => 'Conn-Selmer'));
|
||||
|
||||
// case insensitive
|
||||
CS::define('Instrument', 'Family', 'woodwind', 'istring', 'What family is it?');
|
||||
CS::defineAllowedValues('Instrument', 'Family', array(
|
||||
'brass', 'woodwind', 'percussion', 'string', 'keyboard', 'electronic'));
|
||||
CS::defineValueAliases('Instrument', 'Family', array(
|
||||
'synth' => 'electronic'));
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->autoFinalize = false;
|
||||
|
||||
// case sensitive
|
||||
|
||||
$config->set('Instrument', 'Manufacturer', 'Vandoren');
|
||||
$this->assertIdentical($config->get('Instrument', 'Manufacturer'), 'Vandoren');
|
||||
|
||||
$config->set('Instrument', 'Manufacturer', 'Selmer');
|
||||
$this->assertIdentical($config->get('Instrument', 'Manufacturer'), 'Conn-Selmer');
|
||||
|
||||
$this->expectError('Value not supported, valid values are: Yamaha, Conn-Selmer, Vandoren, Laubin, Buffet, other');
|
||||
$config->set('Instrument', 'Manufacturer', 'buffet');
|
||||
|
||||
// case insensitive
|
||||
|
||||
$config->set('Instrument', 'Family', 'brass');
|
||||
$this->assertIdentical($config->get('Instrument', 'Family'), 'brass');
|
||||
|
||||
$config->set('Instrument', 'Family', 'PERCUSSION');
|
||||
$this->assertIdentical($config->get('Instrument', 'Family'), 'percussion');
|
||||
|
||||
$config->set('Instrument', 'Family', 'synth');
|
||||
$this->assertIdentical($config->get('Instrument', 'Family'), 'electronic');
|
||||
|
||||
$config->set('Instrument', 'Family', 'Synth');
|
||||
$this->assertIdentical($config->get('Instrument', 'Family'), 'electronic');
|
||||
|
||||
}
|
||||
|
||||
function testNull() {
|
||||
|
||||
CS::defineNamespace('ReportCard', 'It is for grades.');
|
||||
CS::define('ReportCard', 'English', null, 'string/null', 'Grade from English class.');
|
||||
CS::define('ReportCard', 'Absences', 0, 'int', 'How many times missing from school?');
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->autoFinalize = false;
|
||||
|
||||
$config->set('ReportCard', 'English', 'B-');
|
||||
$this->assertIdentical($config->get('ReportCard', 'English'), 'B-');
|
||||
|
||||
$config->set('ReportCard', 'English', null); // not yet graded
|
||||
$this->assertIdentical($config->get('ReportCard', 'English'), null);
|
||||
|
||||
// error
|
||||
$this->expectError('Value for ReportCard.Absences is of invalid type, should be int');
|
||||
$config->set('ReportCard', 'Absences', null);
|
||||
|
||||
}
|
||||
|
||||
function testAliases() {
|
||||
|
||||
CS::defineNamespace('Home', 'Sweet home.');
|
||||
CS::define('Home', 'Rug', 3, 'int', 'ID.');
|
||||
CS::defineAlias('Home', 'Carpet', 'Home', 'Rug');
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->autoFinalize = false;
|
||||
|
||||
$this->assertIdentical($config->get('Home', 'Rug'), 3);
|
||||
|
||||
$this->expectError('Cannot get value from aliased directive, use real name Home.Rug');
|
||||
$config->get('Home', 'Carpet');
|
||||
|
||||
$config->set('Home', 'Carpet', 999);
|
||||
$this->assertIdentical($config->get('Home', 'Rug'), 999);
|
||||
|
||||
}
|
||||
|
||||
// test functionality based on method
|
||||
|
||||
function test_getBatch() {
|
||||
|
||||
CS::defineNamespace('Variables', 'Changing quantities in equation.');
|
||||
CS::define('Variables', 'TangentialAcceleration', 'a_tan', 'string', 'In m/s^2');
|
||||
CS::define('Variables', 'AngularAcceleration', 'alpha', 'string', 'In rad/s^2');
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->autoFinalize = false;
|
||||
|
||||
// grab a namespace
|
||||
$this->assertIdentical(
|
||||
$config->getBatch('Variables'),
|
||||
array(
|
||||
'TangentialAcceleration' => 'a_tan',
|
||||
'AngularAcceleration' => 'alpha'
|
||||
)
|
||||
);
|
||||
|
||||
// grab a non-existant namespace
|
||||
$this->expectError('Cannot retrieve undefined namespace Constants');
|
||||
$config->getBatch('Constants');
|
||||
|
||||
}
|
||||
|
||||
function test_loadIni() {
|
||||
|
||||
CS::defineNamespace('Shortcut', 'Keyboard shortcuts for commands');
|
||||
CS::define('Shortcut', 'Copy', 'c', 'istring', 'Copy text');
|
||||
CS::define('Shortcut', 'Paste', 'v', 'istring', 'Paste clipboard');
|
||||
CS::define('Shortcut', 'Cut', 'x', 'istring', 'Cut text');
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->autoFinalize = false;
|
||||
|
||||
$config->loadIni(dirname(__FILE__) . '/ConfigTest-loadIni.ini');
|
||||
|
||||
$this->assertIdentical($config->get('Shortcut', 'Copy'), 'q');
|
||||
$this->assertIdentical($config->get('Shortcut', 'Paste'), 'p');
|
||||
$this->assertIdentical($config->get('Shortcut', 'Cut'), 't');
|
||||
|
||||
}
|
||||
|
||||
function test_getHTMLDefinition() {
|
||||
|
||||
// we actually want to use the old copy, because the definition
|
||||
// generation routines have dependencies on configuration values
|
||||
|
||||
$this->old_copy = HTMLPurifier_ConfigSchema::instance($this->old_copy);
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML', 'Doctype', 'XHTML 1.0 Strict');
|
||||
$config->autoFinalize = false;
|
||||
|
||||
$def = $config->getCSSDefinition();
|
||||
$this->assertIsA($def, 'HTMLPurifier_CSSDefinition');
|
||||
|
||||
$def =& $config->getHTMLDefinition();
|
||||
$def2 =& $config->getHTMLDefinition();
|
||||
$this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
|
||||
$this->assertReference($def, $def2);
|
||||
$this->assertTrue($def->setup);
|
||||
|
||||
// test re-calculation if HTML changes
|
||||
unset($def, $def2);
|
||||
$def2 = $config->getHTMLDefinition(); // forcibly de-reference
|
||||
|
||||
$config->set('HTML', 'Doctype', 'HTML 4.01 Transitional');
|
||||
$def = $config->getHTMLDefinition();
|
||||
$this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
|
||||
$this->assertNotEqual($def, $def2);
|
||||
$this->assertTrue($def->setup);
|
||||
|
||||
// test retrieval of raw definition
|
||||
$config->set('HTML', 'DefinitionID', 'HTMLPurifier_ConfigTest->test_getHTMLDefinition()');
|
||||
$config->set('HTML', 'DefinitionRev', 3);
|
||||
$def =& $config->getHTMLDefinition(true);
|
||||
$this->assertNotEqual($def, $def2);
|
||||
$this->assertEqual(false, $def->setup);
|
||||
|
||||
// auto initialization
|
||||
$config->getHTMLDefinition();
|
||||
$this->assertTrue($def->setup);
|
||||
|
||||
}
|
||||
|
||||
function test_getHTMLDefinition_rawError() {
|
||||
$this->old_copy = HTMLPurifier_ConfigSchema::instance($this->old_copy);
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$this->expectError('Cannot retrieve raw version without specifying %HTML.DefinitionID');
|
||||
$def =& $config->getHTMLDefinition(true);
|
||||
}
|
||||
|
||||
function test_getCSSDefinition() {
|
||||
$this->old_copy = HTMLPurifier_ConfigSchema::instance($this->old_copy);
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$def = $config->getCSSDefinition();
|
||||
$this->assertIsA($def, 'HTMLPurifier_CSSDefinition');
|
||||
}
|
||||
|
||||
function test_getDefinition() {
|
||||
CS::defineNamespace('Cache', 'Cache stuff');
|
||||
CS::define('Cache', 'DefinitionImpl', null, 'string/null', 'Cache?');
|
||||
CS::defineNamespace('Crust', 'Krusty Krabs');
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$this->expectError("Definition of Crust type not supported");
|
||||
$config->getDefinition('Crust');
|
||||
}
|
||||
|
||||
function test_loadArray() {
|
||||
// setup a few dummy namespaces/directives for our testing
|
||||
CS::defineNamespace('Zoo', 'Animals we have.');
|
||||
CS::define('Zoo', 'Aadvark', 0, 'int', 'Have?');
|
||||
CS::define('Zoo', 'Boar', 0, 'int', 'Have?');
|
||||
CS::define('Zoo', 'Camel', 0, 'int', 'Have?');
|
||||
CS::define(
|
||||
'Zoo', 'Others', array(), 'list', 'Other animals we have one of.'
|
||||
);
|
||||
|
||||
$config_manual = HTMLPurifier_Config::createDefault();
|
||||
$config_loadabbr = HTMLPurifier_Config::createDefault();
|
||||
$config_loadfull = HTMLPurifier_Config::createDefault();
|
||||
|
||||
$config_manual->set('Zoo', 'Aadvark', 3);
|
||||
$config_manual->set('Zoo', 'Boar', 5);
|
||||
$config_manual->set('Zoo', 'Camel', 2000); // that's a lotta camels!
|
||||
$config_manual->set('Zoo', 'Others', array('Peacock', 'Dodo')); // wtf!
|
||||
|
||||
// condensed form
|
||||
$config_loadabbr->loadArray(array(
|
||||
'Zoo.Aadvark' => 3,
|
||||
'Zoo.Boar' => 5,
|
||||
'Zoo.Camel' => 2000,
|
||||
'Zoo.Others' => array('Peacock', 'Dodo')
|
||||
));
|
||||
|
||||
// fully expanded form
|
||||
$config_loadfull->loadArray(array(
|
||||
'Zoo' => array(
|
||||
'Aadvark' => 3,
|
||||
'Boar' => 5,
|
||||
'Camel' => 2000,
|
||||
'Others' => array('Peacock', 'Dodo')
|
||||
)
|
||||
));
|
||||
|
||||
$this->assertIdentical($config_manual, $config_loadabbr);
|
||||
$this->assertIdentical($config_manual, $config_loadfull);
|
||||
|
||||
}
|
||||
|
||||
function test_create() {
|
||||
|
||||
CS::defineNamespace('Cake', 'Properties of it.');
|
||||
CS::define('Cake', 'Sprinkles', 666, 'int', 'Number of.');
|
||||
CS::define('Cake', 'Flavor', 'vanilla', 'string', 'Flavor of the batter.');
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('Cake', 'Sprinkles', 42);
|
||||
|
||||
// test flat pass-through
|
||||
$created_config = HTMLPurifier_Config::create($config);
|
||||
$this->assertIdentical($config, $created_config);
|
||||
|
||||
// test loadArray
|
||||
$created_config = HTMLPurifier_Config::create(array('Cake.Sprinkles' => 42));
|
||||
$this->assertIdentical($config, $created_config);
|
||||
|
||||
// test loadIni
|
||||
$created_config = HTMLPurifier_Config::create(dirname(__FILE__) . '/ConfigTest-create.ini');
|
||||
$this->assertIdentical($config, $created_config);
|
||||
|
||||
}
|
||||
|
||||
function test_finalize() {
|
||||
|
||||
// test finalization
|
||||
|
||||
CS::defineNamespace('Poem', 'Violets are red, roses are blue...');
|
||||
CS::define('Poem', 'Meter', 'iambic', 'string', 'Rhythm of poem.');
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->autoFinalize = false;
|
||||
|
||||
$config->set('Poem', 'Meter', 'irregular');
|
||||
|
||||
$config->finalize();
|
||||
|
||||
$this->expectError('Cannot set directive after finalization');
|
||||
$config->set('Poem', 'Meter', 'vedic');
|
||||
|
||||
$this->expectError('Cannot load directives after finalization');
|
||||
$config->loadArray(array('Poem.Meter' => 'octosyllable'));
|
||||
|
||||
$this->expectError('Cannot load directives after finalization');
|
||||
$config->loadIni(dirname(__FILE__) . '/ConfigTest-finalize.ini');
|
||||
|
||||
}
|
||||
|
||||
function test_loadArrayFromForm() {
|
||||
|
||||
CS::defineNamespace('Pancake', 'This should not be user customizable');
|
||||
CS::define('Pancake', 'Mix', 'buttermilk', 'string', 'Type of pancake mix to use.');
|
||||
CS::define('Pancake', 'Served', true, 'bool', 'But this is customizable by user.');
|
||||
CS::defineNamespace('Toppings', 'This is user customizable');
|
||||
CS::define('Toppings', 'Syrup', true, 'bool', 'Absolutely standard!');
|
||||
CS::define('Toppings', 'Flavor', 'maple', 'string', 'What flavor is the syrup?');
|
||||
CS::define('Toppings', 'Strawberries', 3, 'int', 'Quite delightful fruit.');
|
||||
CS::define('Toppings', 'Calories', 2000, 'int/null', 'Some things are best left unknown.');
|
||||
CS::define('Toppings', 'DefinitionID', null, 'string/null', 'Do not let this be set');
|
||||
CS::define('Toppings', 'DefinitionRev', 1, 'int', 'Do not let this be set');
|
||||
CS::define('Toppings', 'Protected', 1, 'int', 'Do not let this be set');
|
||||
|
||||
$get = array(
|
||||
'breakfast' => array(
|
||||
'Pancake.Mix' => 'nasty',
|
||||
'Pancake.Served' => '0',
|
||||
'Toppings.Syrup' => '0',
|
||||
'Toppings.Flavor' => "juice",
|
||||
'Toppings.Strawberries' => '999',
|
||||
'Toppings.Calories' => '',
|
||||
'Null_Toppings.Calories' => '1',
|
||||
'Toppings.DefinitionID' => '<argh>',
|
||||
'Toppings.DefinitionRev' => '65',
|
||||
'Toppings.Protected' => '4',
|
||||
)
|
||||
);
|
||||
|
||||
$config_expect = HTMLPurifier_Config::create(array(
|
||||
'Pancake.Served' => false,
|
||||
'Toppings.Syrup' => false,
|
||||
'Toppings.Flavor' => "juice",
|
||||
'Toppings.Strawberries' => 999,
|
||||
'Toppings.Calories' => null
|
||||
));
|
||||
|
||||
$config_result = HTMLPurifier_Config::loadArrayFromForm($get, 'breakfast', array('Pancake.Served', 'Toppings', '-Toppings.Protected'));
|
||||
|
||||
$this->assertEqual($config_expect, $config_result);
|
||||
|
||||
/*
|
||||
MAGIC QUOTES NOT TESTED!!!
|
||||
|
||||
$get = array(
|
||||
'breakfast' => array(
|
||||
'Pancake.Mix' => 'n\\asty'
|
||||
)
|
||||
);
|
||||
$config_expect = HTMLPurifier_Config::create(array(
|
||||
'Pancake.Mix' => 'n\\asty'
|
||||
));
|
||||
$config_result = HTMLPurifier_Config::loadArrayFromForm($get, 'breakfast', true, false);
|
||||
$this->assertEqual($config_expect, $config_result);
|
||||
*/
|
||||
}
|
||||
|
||||
function test_getAllowedDirectivesForForm() {
|
||||
CS::defineNamespace('Unused', 'Not mentioned, so deny');
|
||||
CS::define('Unused', 'Unused', 'Foobar', 'string', 'Not mentioned, do not allow');
|
||||
CS::defineNamespace('Partial', 'Some are mentioned, allow only those');
|
||||
CS::define('Partial', 'Allowed', true, 'bool', 'Mentioned, allowed');
|
||||
CS::define('Partial', 'Unused', 'Foobar', 'string', 'Not mentioned, do not allow');
|
||||
CS::defineNamespace('All', 'Entire namespace allowed, allow all unless...');
|
||||
CS::define('All', 'Allowed', true, 'bool', 'Not mentioned, allowed');
|
||||
CS::define('All', 'Blacklisted', 'Foobar', 'string', 'Specifically blacklisted');
|
||||
CS::define('All', 'DefinitionID', 'Foobar', 'string/null', 'Special case, auto-blacklisted');
|
||||
CS::define('All', 'DefinitionRev', 2, 'int', 'Special case, auto-blacklisted');
|
||||
|
||||
$input = array('Partial.Allowed', 'All', '-All.Blacklisted');
|
||||
$output = HTMLPurifier_Config::getAllowedDirectivesForForm($input);
|
||||
$expect = array(
|
||||
array('Partial', 'Allowed'),
|
||||
array('All', 'Allowed')
|
||||
);
|
||||
|
||||
$this->assertEqual($output, $expect);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/Context.php';
|
||||
|
||||
// mocks
|
||||
require_once 'HTMLPurifier/IDAccumulator.php';
|
||||
|
||||
class HTMLPurifier_ContextTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
protected $context;
|
||||
|
||||
function setUp() {
|
||||
$this->context = new HTMLPurifier_Context();
|
||||
}
|
||||
|
||||
function testStandardUsage() {
|
||||
|
||||
generate_mock_once('HTMLPurifier_IDAccumulator');
|
||||
|
||||
$this->assertFalse($this->context->exists('IDAccumulator'));
|
||||
|
||||
$accumulator = new HTMLPurifier_IDAccumulatorMock();
|
||||
$this->context->register('IDAccumulator', $accumulator);
|
||||
$this->assertTrue($this->context->exists('IDAccumulator'));
|
||||
|
||||
$accumulator_2 =& $this->context->get('IDAccumulator');
|
||||
$this->assertReference($accumulator, $accumulator_2);
|
||||
|
||||
$this->context->destroy('IDAccumulator');
|
||||
$this->assertFalse($this->context->exists('IDAccumulator'));
|
||||
|
||||
$this->expectError('Attempted to retrieve non-existent variable IDAccumulator');
|
||||
$accumulator_3 =& $this->context->get('IDAccumulator');
|
||||
$this->assertNull($accumulator_3);
|
||||
|
||||
$this->expectError('Attempted to destroy non-existent variable IDAccumulator');
|
||||
$this->context->destroy('IDAccumulator');
|
||||
|
||||
}
|
||||
|
||||
function testReRegister() {
|
||||
|
||||
$var = true;
|
||||
$this->context->register('OnceOnly', $var);
|
||||
|
||||
$this->expectError('Name OnceOnly produces collision, cannot re-register');
|
||||
$this->context->register('OnceOnly', $var);
|
||||
|
||||
// destroy it, now registration is okay
|
||||
$this->context->destroy('OnceOnly');
|
||||
$this->context->register('OnceOnly', $var);
|
||||
|
||||
}
|
||||
|
||||
function test_loadArray() {
|
||||
|
||||
// references can be *really* wonky!
|
||||
|
||||
$context_manual = new HTMLPurifier_Context();
|
||||
$context_load = new HTMLPurifier_Context();
|
||||
|
||||
$var1 = 1;
|
||||
$var2 = 2;
|
||||
|
||||
$context_manual->register('var1', $var1);
|
||||
$context_manual->register('var2', $var2);
|
||||
|
||||
// you MUST set up the references when constructing the array,
|
||||
// otherwise the registered version will be a copy
|
||||
$array = array(
|
||||
'var1' => &$var1,
|
||||
'var2' => &$var2
|
||||
);
|
||||
|
||||
$context_load->loadArray($array);
|
||||
$this->assertIdentical($context_manual, $context_load);
|
||||
|
||||
$var1 = 10;
|
||||
$var2 = 20;
|
||||
|
||||
$this->assertIdentical($context_manual, $context_load);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DefinitionCache/DecoratorHarness.php';
|
||||
require_once 'HTMLPurifier/DefinitionCache/Decorator/Cleanup.php';
|
||||
|
||||
generate_mock_once('HTMLPurifier_DefinitionCache');
|
||||
|
||||
class HTMLPurifier_DefinitionCache_Decorator_CleanupTest extends HTMLPurifier_DefinitionCache_DecoratorHarness
|
||||
{
|
||||
|
||||
function setup() {
|
||||
$this->cache = new HTMLPurifier_DefinitionCache_Decorator_Cleanup();
|
||||
parent::setup();
|
||||
}
|
||||
|
||||
function setupMockForSuccess($op) {
|
||||
$this->mock->expectOnce($op, array($this->def, $this->config));
|
||||
$this->mock->setReturnValue($op, true, array($this->def, $this->config));
|
||||
$this->mock->expectNever('cleanup');
|
||||
}
|
||||
|
||||
function setupMockForFailure($op) {
|
||||
$this->mock->expectOnce($op, array($this->def, $this->config));
|
||||
$this->mock->setReturnValue($op, false, array($this->def, $this->config));
|
||||
$this->mock->expectOnce('cleanup', array($this->config));
|
||||
}
|
||||
|
||||
function test_get() {
|
||||
$this->mock->expectOnce('get', array($this->config));
|
||||
$this->mock->setReturnValue('get', true, array($this->config));
|
||||
$this->mock->expectNever('cleanup');
|
||||
$this->assertEqual($this->cache->get($this->config), $this->def);
|
||||
}
|
||||
|
||||
function test_get_failure() {
|
||||
$this->mock->expectOnce('get', array($this->config));
|
||||
$this->mock->setReturnValue('get', false, array($this->config));
|
||||
$this->mock->expectOnce('cleanup', array($this->config));
|
||||
$this->assertEqual($this->cache->get($this->config), false);
|
||||
}
|
||||
|
||||
function test_set() {
|
||||
$this->setupMockForSuccess('set');
|
||||
$this->assertEqual($this->cache->set($this->def, $this->config), true);
|
||||
}
|
||||
|
||||
function test_replace() {
|
||||
$this->setupMockForSuccess('replace');
|
||||
$this->assertEqual($this->cache->replace($this->def, $this->config), true);
|
||||
}
|
||||
|
||||
function test_add() {
|
||||
$this->setupMockForSuccess('add');
|
||||
$this->assertEqual($this->cache->add($this->def, $this->config), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DefinitionCache/DecoratorHarness.php';
|
||||
require_once 'HTMLPurifier/DefinitionCache/Decorator/Memory.php';
|
||||
|
||||
generate_mock_once('HTMLPurifier_DefinitionCache');
|
||||
|
||||
class HTMLPurifier_DefinitionCache_Decorator_MemoryTest extends HTMLPurifier_DefinitionCache_DecoratorHarness
|
||||
{
|
||||
|
||||
function setup() {
|
||||
$this->cache = new HTMLPurifier_DefinitionCache_Decorator_Memory();
|
||||
parent::setup();
|
||||
}
|
||||
|
||||
function setupMockForSuccess($op) {
|
||||
$this->mock->expectOnce($op, array($this->def, $this->config));
|
||||
$this->mock->setReturnValue($op, true, array($this->def, $this->config));
|
||||
$this->mock->expectNever('get');
|
||||
}
|
||||
|
||||
function setupMockForFailure($op) {
|
||||
$this->mock->expectOnce($op, array($this->def, $this->config));
|
||||
$this->mock->setReturnValue($op, false, array($this->def, $this->config));
|
||||
$this->mock->expectOnce('get', array($this->config));
|
||||
}
|
||||
|
||||
function test_get() {
|
||||
$this->mock->expectOnce('get', array($this->config)); // only ONE call!
|
||||
$this->mock->setReturnValue('get', $this->def, array($this->config));
|
||||
$this->assertEqual($this->cache->get($this->config), $this->def);
|
||||
$this->assertEqual($this->cache->get($this->config), $this->def);
|
||||
}
|
||||
|
||||
function test_set() {
|
||||
$this->setupMockForSuccess('set', 'get');
|
||||
$this->assertEqual($this->cache->set($this->def, $this->config), true);
|
||||
$this->assertEqual($this->cache->get($this->config), $this->def);
|
||||
}
|
||||
|
||||
function test_set_failure() {
|
||||
$this->setupMockForFailure('set', 'get');
|
||||
$this->assertEqual($this->cache->set($this->def, $this->config), false);
|
||||
$this->cache->get($this->config);
|
||||
}
|
||||
|
||||
function test_replace() {
|
||||
$this->setupMockForSuccess('replace', 'get');
|
||||
$this->assertEqual($this->cache->replace($this->def, $this->config), true);
|
||||
$this->assertEqual($this->cache->get($this->config), $this->def);
|
||||
}
|
||||
|
||||
function test_replace_failure() {
|
||||
$this->setupMockForFailure('replace', 'get');
|
||||
$this->assertEqual($this->cache->replace($this->def, $this->config), false);
|
||||
$this->cache->get($this->config);
|
||||
}
|
||||
|
||||
function test_add() {
|
||||
$this->setupMockForSuccess('add', 'get');
|
||||
$this->assertEqual($this->cache->add($this->def, $this->config), true);
|
||||
$this->assertEqual($this->cache->get($this->config), $this->def);
|
||||
}
|
||||
|
||||
function test_add_failure() {
|
||||
$this->setupMockForFailure('add', 'get');
|
||||
$this->assertEqual($this->cache->add($this->def, $this->config), false);
|
||||
$this->cache->get($this->config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DefinitionCacheHarness.php';
|
||||
require_once 'HTMLPurifier/DefinitionCache/Decorator/Memory.php';
|
||||
|
||||
generate_mock_once('HTMLPurifier_DefinitionCache');
|
||||
|
||||
class HTMLPurifier_DefinitionCache_DecoratorHarness extends HTMLPurifier_DefinitionCacheHarness
|
||||
{
|
||||
|
||||
function setup() {
|
||||
$this->mock = new HTMLPurifier_DefinitionCacheMock();
|
||||
$this->mock->type = 'Test';
|
||||
$this->cache = $this->cache->decorate($this->mock);
|
||||
$this->def = $this->generateDefinition();
|
||||
$this->config = $this->generateConfigMock();
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
unset($this->mock);
|
||||
unset($this->cache);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DefinitionCacheHarness.php';
|
||||
require_once 'HTMLPurifier/DefinitionCache/Decorator.php';
|
||||
|
||||
class HTMLPurifier_DefinitionCache_DecoratorTest extends HTMLPurifier_DefinitionCacheHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
generate_mock_once('HTMLPurifier_DefinitionCache');
|
||||
$mock = new HTMLPurifier_DefinitionCacheMock();
|
||||
$mock->type = 'Test';
|
||||
|
||||
$cache = new HTMLPurifier_DefinitionCache_Decorator();
|
||||
$cache = $cache->decorate($mock);
|
||||
|
||||
$this->assertIdentical($cache->type, $mock->type);
|
||||
|
||||
$def = $this->generateDefinition();
|
||||
$config = $this->generateConfigMock();
|
||||
|
||||
$mock->expectOnce('add', array($def, $config));
|
||||
$cache->add($def, $config);
|
||||
|
||||
$mock->expectOnce('set', array($def, $config));
|
||||
$cache->set($def, $config);
|
||||
|
||||
$mock->expectOnce('replace', array($def, $config));
|
||||
$cache->replace($def, $config);
|
||||
|
||||
$mock->expectOnce('get', array($config));
|
||||
$cache->get($config);
|
||||
|
||||
$mock->expectOnce('flush', array($config));
|
||||
$cache->flush($config);
|
||||
|
||||
$mock->expectOnce('cleanup', array($config));
|
||||
$cache->cleanup($config);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DefinitionCacheHarness.php';
|
||||
require_once 'HTMLPurifier/DefinitionCache/Serializer.php';
|
||||
|
||||
class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_DefinitionCacheHarness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
|
||||
|
||||
$config = $this->generateConfigMock('serial');
|
||||
$config->setReturnValue('get', 2, array('Test', 'DefinitionRev'));
|
||||
$config->version = '1.0.0';
|
||||
|
||||
$config_md5 = '1.0.0-serial-2';
|
||||
|
||||
$file = realpath(
|
||||
$rel_file = HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer/Test/' .
|
||||
$config_md5 . '.ser'
|
||||
);
|
||||
if($file && file_exists($file)) unlink($file); // prevent previous failures from causing problems
|
||||
|
||||
$this->assertIdentical($config_md5, $cache->generateKey($config));
|
||||
|
||||
$def_original = $this->generateDefinition();
|
||||
|
||||
$cache->add($def_original, $config);
|
||||
$this->assertFileExist($rel_file);
|
||||
|
||||
$file_generated = $cache->generateFilePath($config);
|
||||
$this->assertIdentical(realpath($rel_file), realpath($file_generated));
|
||||
|
||||
$def_1 = $cache->get($config);
|
||||
$this->assertIdentical($def_original, $def_1);
|
||||
|
||||
$def_original->info_random = 'changed';
|
||||
|
||||
$cache->set($def_original, $config);
|
||||
$def_2 = $cache->get($config);
|
||||
|
||||
$this->assertIdentical($def_original, $def_2);
|
||||
$this->assertNotEqual ($def_original, $def_1);
|
||||
|
||||
$def_original->info_random = 'did it change?';
|
||||
|
||||
$this->assertFalse($cache->add($def_original, $config));
|
||||
$def_3 = $cache->get($config);
|
||||
|
||||
$this->assertNotEqual ($def_original, $def_3); // did not change!
|
||||
$this->assertIdentical($def_3, $def_2);
|
||||
|
||||
$cache->replace($def_original, $config);
|
||||
$def_4 = $cache->get($config);
|
||||
$this->assertIdentical($def_original, $def_4);
|
||||
|
||||
$cache->remove($config);
|
||||
$this->assertFileNotExist($file);
|
||||
|
||||
$this->assertFalse($cache->replace($def_original, $config));
|
||||
$def_5 = $cache->get($config);
|
||||
$this->assertFalse($def_5);
|
||||
|
||||
}
|
||||
|
||||
function test_errors() {
|
||||
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
|
||||
$def = $this->generateDefinition();
|
||||
$def->setup = true;
|
||||
$def->type = 'NotTest';
|
||||
$config = $this->generateConfigMock('testfoo');
|
||||
|
||||
$this->expectError('Cannot use definition of type NotTest in cache for Test');
|
||||
$cache->add($def, $config);
|
||||
|
||||
$this->expectError('Cannot use definition of type NotTest in cache for Test');
|
||||
$cache->set($def, $config);
|
||||
|
||||
$this->expectError('Cannot use definition of type NotTest in cache for Test');
|
||||
$cache->replace($def, $config);
|
||||
}
|
||||
|
||||
function test_flush() {
|
||||
|
||||
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
|
||||
|
||||
$config1 = $this->generateConfigMock('test1');
|
||||
$config2 = $this->generateConfigMock('test2');
|
||||
$config3 = $this->generateConfigMock('test3');
|
||||
|
||||
$def1 = $this->generateDefinition(array('info_candles' => 1));
|
||||
$def2 = $this->generateDefinition(array('info_candles' => 2));
|
||||
$def3 = $this->generateDefinition(array('info_candles' => 3));
|
||||
|
||||
$cache->add($def1, $config1);
|
||||
$cache->add($def2, $config2);
|
||||
$cache->add($def3, $config3);
|
||||
|
||||
$this->assertEqual($def1, $cache->get($config1));
|
||||
$this->assertEqual($def2, $cache->get($config2));
|
||||
$this->assertEqual($def3, $cache->get($config3));
|
||||
|
||||
$cache->flush($config1); // only essential directive is %Cache.SerializerPath
|
||||
|
||||
$this->assertFalse($cache->get($config1));
|
||||
$this->assertFalse($cache->get($config2));
|
||||
$this->assertFalse($cache->get($config3));
|
||||
|
||||
}
|
||||
|
||||
function testCleanup() {
|
||||
|
||||
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
|
||||
|
||||
// in order of age, oldest first
|
||||
// note that configurations are all identical, but version/revision
|
||||
// are different
|
||||
|
||||
$config1 = $this->generateConfigMock();
|
||||
$config1->version = '0.9.0';
|
||||
$config1->setReturnValue('get', 574, array('Test', 'DefinitionRev'));
|
||||
$def1 = $this->generateDefinition(array('info' => 1));
|
||||
|
||||
$config2 = $this->generateConfigMock();
|
||||
$config2->version = '1.0.0beta';
|
||||
$config2->setReturnValue('get', 1, array('Test', 'DefinitionRev'));
|
||||
$def2 = $this->generateDefinition(array('info' => 3));
|
||||
|
||||
$cache->set($def1, $config1);
|
||||
$cache->cleanup($config1);
|
||||
$this->assertEqual($def1, $cache->get($config1)); // no change
|
||||
|
||||
$cache->cleanup($config2);
|
||||
$this->assertFalse($cache->get($config1));
|
||||
$this->assertFalse($cache->get($config2));
|
||||
|
||||
}
|
||||
|
||||
function testCleanupOnlySameID() {
|
||||
|
||||
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
|
||||
|
||||
$config1 = $this->generateConfigMock('serial1');
|
||||
$config1->version = '1.0.0';
|
||||
$config1->setReturnValue('get', 1, array('Test', 'DefinitionRev'));
|
||||
$def1 = $this->generateDefinition(array('info' => 1));
|
||||
|
||||
$config2 = $this->generateConfigMock('serial2');
|
||||
$config2->version = '1.0.0';
|
||||
$config2->setReturnValue('get', 34, array('Test', 'DefinitionRev'));
|
||||
$def2 = $this->generateDefinition(array('info' => 3));
|
||||
|
||||
$cache->set($def1, $config1);
|
||||
$cache->cleanup($config1);
|
||||
$this->assertEqual($def1, $cache->get($config1)); // no change
|
||||
|
||||
$cache->set($def2, $config2);
|
||||
$cache->cleanup($config2);
|
||||
$this->assertEqual($def1, $cache->get($config1));
|
||||
$this->assertEqual($def2, $cache->get($config2));
|
||||
|
||||
$cache->flush($config1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a file exists, ignoring the stat cache
|
||||
*/
|
||||
function assertFileExist($file) {
|
||||
clearstatcache();
|
||||
$this->assertTrue(file_exists($file), 'Expected ' . $file . ' exists');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a file does not exist, ignoring the stat cache
|
||||
*/
|
||||
function assertFileNotExist($file) {
|
||||
$this->assertFalse(file_exists($file), 'Expected ' . $file . ' does not exist');
|
||||
}
|
||||
|
||||
function testAlternatePath() {
|
||||
|
||||
$cache = new HTMLPurifier_DefinitionCache_Serializer('Test');
|
||||
$config = $this->generateConfigMock('serial');
|
||||
$config->version = '1.0.0';
|
||||
$config->setReturnValue('get', 1, array('Test', 'DefinitionRev'));
|
||||
$dir = dirname(__FILE__) . '/SerializerTest';
|
||||
$config->setReturnValue('get', $dir, array('Cache', 'SerializerPath'));
|
||||
|
||||
$def_original = $this->generateDefinition();
|
||||
$cache->add($def_original, $config);
|
||||
$this->assertFileExist($dir . '/Test/1.0.0-serial-1.ser');
|
||||
|
||||
unlink($dir . '/Test/1.0.0-serial-1.ser');
|
||||
rmdir( $dir . '/Test');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DefinitionCacheFactory.php';
|
||||
|
||||
class HTMLPurifier_DefinitionCacheFactoryTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
protected $factory;
|
||||
protected $oldFactory;
|
||||
|
||||
function setup() {
|
||||
parent::setup();
|
||||
$this->factory = new HTMLPurifier_DefinitionCacheFactory();
|
||||
$this->oldFactory = HTMLPurifier_DefinitionCacheFactory::instance();
|
||||
HTMLPurifier_DefinitionCacheFactory::instance($this->factory);
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
HTMLPurifier_DefinitionCacheFactory::instance($this->oldFactory);
|
||||
}
|
||||
|
||||
function test_create() {
|
||||
$cache = $this->factory->create('Test', $this->config);
|
||||
$this->assertEqual($cache, new HTMLPurifier_DefinitionCache_Serializer('Test'));
|
||||
}
|
||||
|
||||
function test_create_withDecorator() {
|
||||
$this->factory->addDecorator('Memory');
|
||||
$cache = $this->factory->create('Test', $this->config);
|
||||
$cache_real = new HTMLPurifier_DefinitionCache_Decorator_Memory();
|
||||
$cache_real = $cache_real->decorate(new HTMLPurifier_DefinitionCache_Serializer('Test'));
|
||||
$this->assertEqual($cache, $cache_real);
|
||||
}
|
||||
|
||||
function test_create_withDecoratorObject() {
|
||||
$this->factory->addDecorator(new HTMLPurifier_DefinitionCache_Decorator_Memory());
|
||||
$cache = $this->factory->create('Test', $this->config);
|
||||
$cache_real = new HTMLPurifier_DefinitionCache_Decorator_Memory();
|
||||
$cache_real = $cache_real->decorate(new HTMLPurifier_DefinitionCache_Serializer('Test'));
|
||||
$this->assertEqual($cache, $cache_real);
|
||||
}
|
||||
|
||||
function test_create_recycling() {
|
||||
$cache = $this->factory->create('Test', $this->config);
|
||||
$cache2 = $this->factory->create('Test', $this->config);
|
||||
$this->assertReference($cache, $cache2);
|
||||
}
|
||||
|
||||
function test_create_invalid() {
|
||||
$this->config->set('Core', 'DefinitionCache', 'Invalid');
|
||||
$this->expectError('Unrecognized DefinitionCache Invalid, using Serializer instead');
|
||||
$cache = $this->factory->create('Test', $this->config);
|
||||
$this->assertIsA($cache, 'HTMLPurifier_DefinitionCache_Serializer');
|
||||
}
|
||||
|
||||
function test_null() {
|
||||
$this->config->set('Core', 'DefinitionCache', null);
|
||||
$cache = $this->factory->create('Test', $this->config);
|
||||
$this->assertEqual($cache, new HTMLPurifier_DefinitionCache_Null('Test'));
|
||||
}
|
||||
|
||||
function test_register() {
|
||||
generate_mock_once('HTMLPurifier_DefinitionCache');
|
||||
$this->config->set('Core', 'DefinitionCache', 'TestCache');
|
||||
$this->factory->register('TestCache', $class = 'HTMLPurifier_DefinitionCacheMock');
|
||||
$cache = $this->factory->create('Test', $this->config);
|
||||
$this->assertIsA($cache, $class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DefinitionTestable.php';
|
||||
|
||||
class HTMLPurifier_DefinitionCacheHarness extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
/**
|
||||
* Generate a configuration mock object that returns $values
|
||||
* to a getBatch() call
|
||||
* @param $values Values to return when getBatch is invoked
|
||||
*/
|
||||
function generateConfigMock($serial = 'defaultserial') {
|
||||
generate_mock_once('HTMLPurifier_Config');
|
||||
$config = new HTMLPurifier_ConfigMock();
|
||||
$config->setReturnValue('getBatchSerial', $serial, array('Test'));
|
||||
$config->version = '1.0.0';
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an anonymous def that has been setup and named Test
|
||||
*/
|
||||
function generateDefinition($member_vars = array()) {
|
||||
$def = new HTMLPurifier_DefinitionTestable();
|
||||
$def->setup = true;
|
||||
$def->type = 'Test';
|
||||
foreach ($member_vars as $key => $val) {
|
||||
$def->$key = $val;
|
||||
}
|
||||
return $def;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DefinitionCache.php';
|
||||
|
||||
class HTMLPurifier_DefinitionCacheTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_isOld() {
|
||||
// using null subclass because parent is abstract
|
||||
$cache = new HTMLPurifier_DefinitionCache_Null('Test');
|
||||
|
||||
$old_copy = HTMLPurifier_ConfigSchema::instance();
|
||||
$o = new HTMLPurifier_ConfigSchema();
|
||||
HTMLPurifier_ConfigSchema::instance($o);
|
||||
|
||||
HTMLPurifier_ConfigSchema::defineNamespace('Test', 'Test namespace');
|
||||
HTMLPurifier_ConfigSchema::define('Test', 'DefinitionRev', 1, 'int', 'Definition revision.');
|
||||
|
||||
generate_mock_once('HTMLPurifier_Config');
|
||||
$config = new HTMLPurifier_ConfigMock();
|
||||
$config->version = '1.0.0'; // hopefully no conflicts
|
||||
$config->setReturnValue('get', 10, array('Test', 'DefinitionRev'));
|
||||
$config->setReturnValue('getBatchSerial', 'hash', array('Test'));
|
||||
|
||||
$this->assertIdentical($cache->isOld('1.0.0-hash-10', $config), false);
|
||||
$this->assertIdentical($cache->isOld('1.5.0-hash-1', $config), true);
|
||||
|
||||
$this->assertIdentical($cache->isOld('0.9.0-hash-1', $config), true);
|
||||
$this->assertIdentical($cache->isOld('1.0.0-hash-1', $config), true);
|
||||
$this->assertIdentical($cache->isOld('1.0.0beta-hash-11', $config), true);
|
||||
|
||||
$this->assertIdentical($cache->isOld('0.9.0-hash2-1', $config), true);
|
||||
$this->assertIdentical($cache->isOld('1.0.0-hash2-1', $config), false); // if hash is different, don't touch!
|
||||
$this->assertIdentical($cache->isOld('1.0.0beta-hash2-11', $config), true);
|
||||
|
||||
HTMLPurifier_ConfigSchema::instance($old_copy);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/Definition.php';
|
||||
require_once 'HTMLPurifier/DefinitionTestable.php';
|
||||
|
||||
class HTMLPurifier_DefinitionTest extends HTMLPurifier_Harness
|
||||
{
|
||||
function test_setup() {
|
||||
$def = new HTMLPurifier_DefinitionTestable();
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$def->expectOnce('doSetup', array($config));
|
||||
$def->setup($config);
|
||||
}
|
||||
function test_setup_redundant() {
|
||||
$def = new HTMLPurifier_DefinitionTestable();
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$def->expectNever('doSetup');
|
||||
$def->setup = true;
|
||||
$def->setup($config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
Mock::generatePartial(
|
||||
'HTMLPurifier_Definition',
|
||||
'HTMLPurifier_DefinitionTestable',
|
||||
array('doSetup'));
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/DoctypeRegistry.php';
|
||||
|
||||
class HTMLPurifier_DoctypeRegistryTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_register() {
|
||||
|
||||
$registry = new HTMLPurifier_DoctypeRegistry();
|
||||
|
||||
$d =& $registry->register(
|
||||
$name = 'XHTML 1.0 Transitional',
|
||||
$xml = true,
|
||||
$modules = array('module-one', 'module-two'),
|
||||
$tidyModules = array('lenient-module'),
|
||||
$aliases = array('X10T')
|
||||
);
|
||||
|
||||
$d2 = new HTMLPurifier_Doctype($name, $xml, $modules, $tidyModules, $aliases);
|
||||
|
||||
$this->assertIdentical($d, $d2);
|
||||
$this->assertReference($d, $registry->get('XHTML 1.0 Transitional'));
|
||||
|
||||
// test shorthand
|
||||
$d =& $registry->register(
|
||||
$name = 'XHTML 1.0 Strict', true, 'module', 'Tidy', 'X10S'
|
||||
);
|
||||
$d2 = new HTMLPurifier_Doctype($name, true, array('module'), array('Tidy'), array('X10S'));
|
||||
|
||||
$this->assertIdentical($d, $d2);
|
||||
|
||||
}
|
||||
|
||||
function test_get() {
|
||||
|
||||
// see also alias and register tests
|
||||
|
||||
$registry = new HTMLPurifier_DoctypeRegistry();
|
||||
|
||||
$this->expectError('Doctype XHTML 2.0 does not exist');
|
||||
$registry->get('XHTML 2.0');
|
||||
|
||||
// prevent XSS
|
||||
$this->expectError('Doctype <foo> does not exist');
|
||||
$registry->get('<foo>');
|
||||
|
||||
}
|
||||
|
||||
function testAliases() {
|
||||
|
||||
$registry = new HTMLPurifier_DoctypeRegistry();
|
||||
|
||||
$d1 =& $registry->register('Doc1', true, array(), array(), array('1'));
|
||||
|
||||
$this->assertReference($d1, $registry->get('Doc1'));
|
||||
$this->assertReference($d1, $registry->get('1'));
|
||||
|
||||
$d2 =& $registry->register('Doc2', true, array(), array(), array('2'));
|
||||
|
||||
$this->assertReference($d2, $registry->get('Doc2'));
|
||||
$this->assertReference($d2, $registry->get('2'));
|
||||
|
||||
$d3 =& $registry->register('1', true, array(), array(), array());
|
||||
|
||||
// literal name overrides alias
|
||||
$this->assertReference($d3, $registry->get('1'));
|
||||
|
||||
$d4 =& $registry->register('One', true, array(), array(), array('1'));
|
||||
|
||||
$this->assertReference($d4, $registry->get('One'));
|
||||
// still it overrides
|
||||
$this->assertReference($d3, $registry->get('1'));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ElementDef.php';
|
||||
|
||||
class HTMLPurifier_ElementDefTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_mergeIn() {
|
||||
|
||||
$def1 = new HTMLPurifier_ElementDef();
|
||||
$def2 = new HTMLPurifier_ElementDef();
|
||||
$def3 = new HTMLPurifier_ElementDef();
|
||||
|
||||
$old = 1;
|
||||
$new = 2;
|
||||
$overloaded_old = 3;
|
||||
$overloaded_new = 4;
|
||||
$removed = 5;
|
||||
|
||||
$def1->standalone = true;
|
||||
$def1->attr = array(
|
||||
0 => array('old-include'),
|
||||
'old-attr' => $old,
|
||||
'overloaded-attr' => $overloaded_old,
|
||||
'removed-attr' => $removed,
|
||||
);
|
||||
$def1->attr_transform_pre =
|
||||
$def1->attr_transform_post = array(
|
||||
'old-transform' => $old,
|
||||
'overloaded-transform' => $overloaded_old,
|
||||
'removed-transform' => $removed,
|
||||
);
|
||||
$def1->child = $overloaded_old;
|
||||
$def1->content_model = 'old';
|
||||
$def1->content_model_type = $overloaded_old;
|
||||
$def1->descendants_are_inline = false;
|
||||
$def1->excludes = array(
|
||||
'old' => true,
|
||||
'removed-old' => true
|
||||
);
|
||||
$def1->safe = false;
|
||||
|
||||
$def2->standalone = false;
|
||||
$def2->attr = array(
|
||||
0 => array('new-include'),
|
||||
'new-attr' => $new,
|
||||
'overloaded-attr' => $overloaded_new,
|
||||
'removed-attr' => false,
|
||||
);
|
||||
$def2->attr_transform_pre =
|
||||
$def2->attr_transform_post = array(
|
||||
'new-transform' => $new,
|
||||
'overloaded-transform' => $overloaded_new,
|
||||
'removed-transform' => false,
|
||||
);
|
||||
$def2->child = $new;
|
||||
$def2->content_model = 'new';
|
||||
$def2->content_model_type = $overloaded_new;
|
||||
$def2->descendants_are_inline = true;
|
||||
$def2->excludes = array(
|
||||
'new' => true,
|
||||
'removed-old' => false
|
||||
);
|
||||
$def2->safe = true;
|
||||
|
||||
$def1->mergeIn($def2);
|
||||
$def1->mergeIn($def3); // empty, has no effect
|
||||
|
||||
$this->assertIdentical($def1->standalone, true);
|
||||
$this->assertIdentical($def1->attr, array(
|
||||
0 => array('old-include', 'new-include'),
|
||||
'old-attr' => $old,
|
||||
'overloaded-attr' => $overloaded_new,
|
||||
'new-attr' => $new,
|
||||
));
|
||||
$this->assertIdentical($def1->attr_transform_pre, $def1->attr_transform_post);
|
||||
$this->assertIdentical($def1->attr_transform_pre, array(
|
||||
'old-transform' => $old,
|
||||
'overloaded-transform' => $overloaded_new,
|
||||
'new-transform' => $new,
|
||||
));
|
||||
$this->assertIdentical($def1->child, $new);
|
||||
$this->assertIdentical($def1->content_model, 'old | new');
|
||||
$this->assertIdentical($def1->content_model_type, $overloaded_new);
|
||||
$this->assertIdentical($def1->descendants_are_inline, true);
|
||||
$this->assertIdentical($def1->excludes, array(
|
||||
'old' => true,
|
||||
'new' => true
|
||||
));
|
||||
$this->assertIdentical($def1->safe, true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/Encoder.php';
|
||||
|
||||
class HTMLPurifier_EncoderTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
protected $_entity_lookup;
|
||||
|
||||
function setUp() {
|
||||
$this->_entity_lookup = HTMLPurifier_EntityLookup::instance();
|
||||
}
|
||||
|
||||
function assertCleanUTF8($string, $expect = null) {
|
||||
if ($expect === null) $expect = $string;
|
||||
$this->assertIdentical(HTMLPurifier_Encoder::cleanUTF8($string), $expect, 'iconv: %s');
|
||||
$this->assertIdentical(HTMLPurifier_Encoder::cleanUTF8($string, true), $expect, 'PHP: %s');
|
||||
}
|
||||
|
||||
function test_cleanUTF8() {
|
||||
$this->assertCleanUTF8('Normal string.');
|
||||
$this->assertCleanUTF8("Test\tAllowed\nControl\rCharacters");
|
||||
$this->assertCleanUTF8("null byte: \0", 'null byte: ');
|
||||
$this->assertCleanUTF8("\1\2\3\4\5\6\7", '');
|
||||
$this->assertCleanUTF8("\x7F", ''); // one byte invalid SGML char
|
||||
$this->assertCleanUTF8("\xC2\x80", ''); // two byte invalid SGML
|
||||
$this->assertCleanUTF8("\xF3\xBF\xBF\xBF"); // valid four byte
|
||||
$this->assertCleanUTF8("\xDF\xFF", ''); // malformed UTF8
|
||||
}
|
||||
|
||||
function test_convertToUTF8() {
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$context = new HTMLPurifier_Context();
|
||||
|
||||
// UTF-8 means that we don't touch it
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertToUTF8("\xF6", $config, $context),
|
||||
"\xF6", // this is invalid
|
||||
'Expected identical [Binary: F6]'
|
||||
);
|
||||
$this->assertNoErrors();
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'Core.Encoding' => 'ISO-8859-1'
|
||||
));
|
||||
|
||||
// Now it gets converted
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertToUTF8("\xF6", $config, $context),
|
||||
"\xC3\xB6"
|
||||
);
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'Core.Encoding' => 'ISO-8859-1',
|
||||
'Test.ForceNoIconv' => true
|
||||
));
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertToUTF8("\xF6", $config, $context),
|
||||
"\xC3\xB6"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_convertFromUTF8() {
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$context = new HTMLPurifier_Context();
|
||||
|
||||
// zhong-wen
|
||||
$chinese = "\xE4\xB8\xAD\xE6\x96\x87 (Chinese)";
|
||||
|
||||
// UTF-8 means that we don't touch it
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertFromUTF8("\xC3\xB6", $config, $context),
|
||||
"\xC3\xB6"
|
||||
);
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'Core.Encoding' => 'ISO-8859-1'
|
||||
));
|
||||
|
||||
// Now it gets converted
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertFromUTF8("\xC3\xB6", $config, $context),
|
||||
"\xF6",
|
||||
'Expected identical [Binary: F6]'
|
||||
);
|
||||
|
||||
if (function_exists('iconv')) {
|
||||
// iconv has it's own way
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertFromUTF8($chinese, $config, $context),
|
||||
" (Chinese)"
|
||||
);
|
||||
}
|
||||
|
||||
// Plain PHP implementation has slightly different behavior
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'Core.Encoding' => 'ISO-8859-1',
|
||||
'Test.ForceNoIconv' => true
|
||||
));
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertFromUTF8("\xC3\xB6", $config, $context),
|
||||
"\xF6",
|
||||
'Expected identical [Binary: F6]'
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertFromUTF8($chinese, $config, $context),
|
||||
"?? (Chinese)"
|
||||
);
|
||||
|
||||
// Preserve the characters!
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'Core.Encoding' => 'ISO-8859-1',
|
||||
'Core.EscapeNonASCIICharacters' => true
|
||||
));
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertFromUTF8($chinese, $config, $context),
|
||||
"中文 (Chinese)"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_convertToASCIIDumbLossless() {
|
||||
|
||||
// Uppercase thorn letter
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertToASCIIDumbLossless("\xC3\x9Eorn"),
|
||||
"Þorn"
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertToASCIIDumbLossless("an"),
|
||||
"an"
|
||||
);
|
||||
|
||||
// test up to four bytes
|
||||
$this->assertIdentical(
|
||||
HTMLPurifier_Encoder::convertToASCIIDumbLossless("\xF3\xA0\x80\xA0"),
|
||||
"󠀠"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
// this page is UTF-8 encoded!
|
||||
|
||||
require_once 'HTMLPurifier/EntityLookup.php';
|
||||
|
||||
class HTMLPurifier_EntityLookupTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
$lookup = HTMLPurifier_EntityLookup::instance();
|
||||
|
||||
// latin char
|
||||
$this->assertIdentical('â', $lookup->table['acirc']);
|
||||
|
||||
// special char
|
||||
$this->assertIdentical('"', $lookup->table['quot']);
|
||||
$this->assertIdentical('“', $lookup->table['ldquo']);
|
||||
$this->assertIdentical('<', $lookup->table['lt']); // expressed strangely in source file
|
||||
|
||||
// symbol char
|
||||
$this->assertIdentical('θ', $lookup->table['theta']);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/EntityParser.php';
|
||||
|
||||
class HTMLPurifier_EntityParserTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
protected $EntityParser;
|
||||
|
||||
function setUp() {
|
||||
$this->EntityParser = new HTMLPurifier_EntityParser();
|
||||
$this->_entity_lookup = HTMLPurifier_EntityLookup::instance();
|
||||
}
|
||||
|
||||
function test_substituteNonSpecialEntities() {
|
||||
$char_theta = $this->_entity_lookup->table['theta'];
|
||||
$this->assertIdentical($char_theta,
|
||||
$this->EntityParser->substituteNonSpecialEntities('θ') );
|
||||
$this->assertIdentical('"',
|
||||
$this->EntityParser->substituteNonSpecialEntities('"') );
|
||||
|
||||
// numeric tests, adapted from Feyd
|
||||
$args = array();
|
||||
$args[] = array(1114112,false );
|
||||
$args[] = array(1114111,'F48FBFBF'); // 0x0010FFFF
|
||||
$args[] = array(1048576,'F4808080'); // 0x00100000
|
||||
$args[] = array(1048575,'F3BFBFBF'); // 0x000FFFFF
|
||||
$args[] = array(262144, 'F1808080'); // 0x00040000
|
||||
$args[] = array(262143, 'F0BFBFBF'); // 0x0003FFFF
|
||||
$args[] = array(65536, 'F0908080'); // 0x00010000
|
||||
$args[] = array(65535, 'EFBFBF' ); // 0x0000FFFF
|
||||
$args[] = array(57344, 'EE8080' ); // 0x0000E000
|
||||
$args[] = array(57343, false ); // 0x0000DFFF these are ill-formed
|
||||
$args[] = array(56040, false ); // 0x0000DAE8 these are ill-formed
|
||||
$args[] = array(55296, false ); // 0x0000D800 these are ill-formed
|
||||
$args[] = array(55295, 'ED9FBF' ); // 0x0000D7FF
|
||||
$args[] = array(53248, 'ED8080' ); // 0x0000D000
|
||||
$args[] = array(53247, 'ECBFBF' ); // 0x0000CFFF
|
||||
$args[] = array(4096, 'E18080' ); // 0x00001000
|
||||
$args[] = array(4095, 'E0BFBF' ); // 0x00000FFF
|
||||
$args[] = array(2048, 'E0A080' ); // 0x00000800
|
||||
$args[] = array(2047, 'DFBF' ); // 0x000007FF
|
||||
$args[] = array(128, 'C280' ); // 0x00000080 invalid SGML char
|
||||
$args[] = array(127, '7F' ); // 0x0000007F invalid SGML char
|
||||
$args[] = array(0, '00' ); // 0x00000000 invalid SGML char
|
||||
|
||||
$args[] = array(20108, 'E4BA8C' ); // 0x00004E8C
|
||||
$args[] = array(77, '4D' ); // 0x0000004D
|
||||
$args[] = array(66306, 'F0908C82'); // 0x00010302
|
||||
$args[] = array(1072, 'D0B0' ); // 0x00000430
|
||||
|
||||
foreach ($args as $arg) {
|
||||
$string = '&#' . $arg[0] . ';' . // decimal
|
||||
'&#x' . dechex($arg[0]) . ';'; // hex
|
||||
$expect = '';
|
||||
if ($arg[1] !== false) {
|
||||
// this is only for PHP 5, the below is PHP 5 and PHP 4
|
||||
//$chars = str_split($arg[1], 2);
|
||||
$chars = array();
|
||||
// strlen must be called in loop because strings size changes
|
||||
for ($i = 0; strlen($arg[1]) > $i; $i += 2) {
|
||||
$chars[] = $arg[1][$i] . $arg[1][$i+1];
|
||||
}
|
||||
foreach ($chars as $char) {
|
||||
$expect .= chr(hexdec($char));
|
||||
}
|
||||
$expect .= $expect; // double it
|
||||
}
|
||||
$this->assertIdentical(
|
||||
$this->EntityParser->substituteNonSpecialEntities($string),
|
||||
$expect,
|
||||
'Identical expectation [Hex: '. dechex($arg[0]) .']'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function test_substituteSpecialEntities() {
|
||||
$this->assertIdentical(
|
||||
"'",
|
||||
$this->EntityParser->substituteSpecialEntities(''')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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
|
||||
{
|
||||
|
||||
private $_context;
|
||||
private $_expected_context = array();
|
||||
private $_expected_context_at = array();
|
||||
|
||||
public function prepare(&$context) {
|
||||
$this->_context =& $context;
|
||||
}
|
||||
|
||||
public function expectContext($key, $value) {
|
||||
$this->_expected_context[$key] = $value;
|
||||
}
|
||||
public function expectContextAt($step, $key, $value) {
|
||||
$this->_expected_context_at[$step][$key] = $value;
|
||||
}
|
||||
|
||||
public function send($v1, $v2) {
|
||||
// test for context
|
||||
$context =& SimpleTest::getContext();
|
||||
$test =& $context->getTest();
|
||||
|
||||
// compat
|
||||
if (empty($this->_mock)) {
|
||||
$mock =& $this;
|
||||
} else {
|
||||
$mock =& $this->_mock;
|
||||
}
|
||||
|
||||
foreach ($this->_expected_context as $key => $value) {
|
||||
$test->assertEqual($value, $this->_context->get($key));
|
||||
}
|
||||
$step = $mock->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();
|
||||
$mock->_invoke('send', $args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ErrorCollector.php';
|
||||
|
||||
class HTMLPurifier_ErrorCollectorTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function setup() {
|
||||
generate_mock_once('HTMLPurifier_Language');
|
||||
generate_mock_once('HTMLPurifier_Generator');
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
||||
$language = new HTMLPurifier_LanguageMock();
|
||||
$language->setReturnValue('getErrorName', 'Error', array(E_ERROR));
|
||||
$language->setReturnValue('getErrorName', 'Warning', array(E_WARNING));
|
||||
$language->setReturnValue('getMessage', 'Message 1', array('message-1'));
|
||||
$language->setReturnValue('formatMessage', 'Message 2', array('message-2', array(1 => 'param')));
|
||||
$language->setReturnValue('formatMessage', ' at line 23', array('ErrorCollector: At line', array('line' => 23)));
|
||||
$language->setReturnValue('formatMessage', ' at line 3', array('ErrorCollector: At line', array('line' => 3)));
|
||||
|
||||
$line = false;
|
||||
|
||||
$context = new HTMLPurifier_Context();
|
||||
$context->register('Locale', $language);
|
||||
$context->register('CurrentLine', $line);
|
||||
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
$context->register('Generator', $generator);
|
||||
|
||||
$collector = new HTMLPurifier_ErrorCollector($context);
|
||||
|
||||
$line = 23;
|
||||
$collector->send(E_ERROR, 'message-1');
|
||||
|
||||
$line = 3;
|
||||
$collector->send(E_WARNING, 'message-2', 'param');
|
||||
|
||||
$result = array(
|
||||
0 => array(23, E_ERROR, 'Message 1'),
|
||||
1 => array(3, E_WARNING, 'Message 2')
|
||||
);
|
||||
|
||||
$this->assertIdentical($collector->getRaw(), $result);
|
||||
|
||||
$formatted_result =
|
||||
'<ul><li><strong>Warning</strong>: Message 2 at line 3</li>'.
|
||||
'<li><strong>Error</strong>: Message 1 at line 23</li></ul>';
|
||||
|
||||
$config = HTMLPurifier_Config::create(array('Core.MaintainLineNumbers' => true));
|
||||
|
||||
$this->assertIdentical($collector->getHTMLFormatted($config), $formatted_result);
|
||||
|
||||
}
|
||||
|
||||
function testNoErrors() {
|
||||
$language = new HTMLPurifier_LanguageMock();
|
||||
$language->setReturnValue('getMessage', 'No errors', array('ErrorCollector: No errors'));
|
||||
$context = new HTMLPurifier_Context();
|
||||
$context->register('Locale', $language);
|
||||
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
$context->register('Generator', $generator);
|
||||
|
||||
$collector = new HTMLPurifier_ErrorCollector($context);
|
||||
$formatted_result = '<p>No errors</p>';
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$this->assertIdentical($collector->getHTMLFormatted($config), $formatted_result);
|
||||
}
|
||||
|
||||
function testNoLineNumbers() {
|
||||
$language = new HTMLPurifier_LanguageMock();
|
||||
$language->setReturnValue('getMessage', 'Message 1', array('message-1'));
|
||||
$language->setReturnValue('getMessage', 'Message 2', array('message-2'));
|
||||
$language->setReturnValue('getErrorName', 'Error', array(E_ERROR));
|
||||
$context = new HTMLPurifier_Context();
|
||||
$context->register('Locale', $language);
|
||||
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
$context->register('Generator', $generator);
|
||||
|
||||
$collector = new HTMLPurifier_ErrorCollector($context);
|
||||
$collector->send(E_ERROR, 'message-1');
|
||||
$collector->send(E_ERROR, 'message-2');
|
||||
|
||||
$result = array(
|
||||
0 => array(null, E_ERROR, 'Message 1'),
|
||||
1 => array(null, E_ERROR, 'Message 2')
|
||||
);
|
||||
$this->assertIdentical($collector->getRaw(), $result);
|
||||
|
||||
$formatted_result =
|
||||
'<ul><li><strong>Error</strong>: Message 1</li>'.
|
||||
'<li><strong>Error</strong>: Message 2</li></ul>';
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$this->assertIdentical($collector->getHTMLFormatted($config), $formatted_result);
|
||||
}
|
||||
|
||||
function testContextSubstitutions() {
|
||||
|
||||
$language = new HTMLPurifier_LanguageMock();
|
||||
$context = new HTMLPurifier_Context();
|
||||
$context->register('Locale', $language);
|
||||
|
||||
$generator = new HTMLPurifier_Generator();
|
||||
$context->register('Generator', $generator);
|
||||
|
||||
$current_token = false;
|
||||
$context->register('CurrentToken', $current_token);
|
||||
|
||||
$collector = new HTMLPurifier_ErrorCollector($context);
|
||||
|
||||
// 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, 'Token message'),
|
||||
1 => array(32, E_NOTICE, '$CurrentAttr.Name => $CurrentAttr.Value'),
|
||||
2 => array(32, E_NOTICE, 'href => http://example.com')
|
||||
);
|
||||
$this->assertIdentical($collector->getRaw(), $result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ErrorCollectorEMock.php';
|
||||
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
||||
|
||||
/**
|
||||
* @todo Make the callCount variable actually work, so we can precisely
|
||||
* specify what errors we want: no more, no less
|
||||
*/
|
||||
class HTMLPurifier_ErrorsHarness extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
protected $config, $context;
|
||||
protected $collector, $generator, $callCount;
|
||||
|
||||
function setup() {
|
||||
$this->config = HTMLPurifier_Config::create(array('Core.CollectErrors' => true));
|
||||
$this->context = new HTMLPurifier_Context();
|
||||
generate_mock_once('HTMLPurifier_ErrorCollector');
|
||||
$this->collector = new HTMLPurifier_ErrorCollectorEMock();
|
||||
$this->collector->prepare($this->context);
|
||||
$this->context->register('ErrorCollector', $this->collector);
|
||||
$this->callCount = 0;
|
||||
}
|
||||
|
||||
function expectNoErrorCollection() {
|
||||
$this->collector->expectNever('send');
|
||||
}
|
||||
|
||||
function expectErrorCollection() {
|
||||
$args = func_get_args();
|
||||
$this->collector->expectOnce('send', $args);
|
||||
}
|
||||
|
||||
function expectContext($key, $value) {
|
||||
$this->collector->expectContext($key, $value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/Filter/ExtractStyleBlocks.php';
|
||||
|
||||
/**
|
||||
* @todo Assimilate CSSTidy into our library
|
||||
*/
|
||||
class HTMLPurifier_Filter_ExtractStyleBlocksTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
// usual use case:
|
||||
function test_tokenizeHTML_extractStyleBlocks() {
|
||||
$purifier = new HTMLPurifier($this->config);
|
||||
$purifier->addFilter(new HTMLPurifier_Filter_ExtractStyleBlocks());
|
||||
$result = $purifier->purify('<style type="text/css">.foo {text-align:center;bogus:remove-me;}</style>Test<style>* {font-size:12pt;}</style>');
|
||||
$this->assertIdentical($result, 'Test');
|
||||
$this->assertIdentical($purifier->context->get('StyleBlocks'),
|
||||
array(
|
||||
".foo {\ntext-align:center;\n}",
|
||||
"* {\nfont-size:12pt;\n}"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function assertExtractStyleBlocks($html, $expect = true, $styles = array()) {
|
||||
$filter = new HTMLPurifier_Filter_ExtractStyleBlocks(false); // disable cleaning
|
||||
if ($expect === true) $expect = $html;
|
||||
$result = $filter->preFilter($html, $this->config, $this->context);
|
||||
$this->assertIdentical($result, $expect);
|
||||
$this->assertIdentical($this->context->get('StyleBlocks'), $styles);
|
||||
}
|
||||
|
||||
function test_extractStyleBlocks_preserve() {
|
||||
$this->assertExtractStyleBlocks('Foobar');
|
||||
}
|
||||
|
||||
function test_extractStyleBlocks_allStyle() {
|
||||
$this->assertExtractStyleBlocks('<style>foo</style>', '', array('foo'));
|
||||
}
|
||||
|
||||
function test_extractStyleBlocks_multipleBlocks() {
|
||||
$this->assertExtractStyleBlocks(
|
||||
"<style>1</style><style>2</style>NOP<style>4</style>",
|
||||
"NOP",
|
||||
array('1', '2', '4')
|
||||
);
|
||||
}
|
||||
|
||||
function test_extractStyleBlocks_blockWithAttributes() {
|
||||
$this->assertExtractStyleBlocks(
|
||||
'<style type="text/css">css</style>',
|
||||
'',
|
||||
array('css')
|
||||
);
|
||||
}
|
||||
|
||||
function test_extractStyleBlocks_styleWithPadding() {
|
||||
$this->assertExtractStyleBlocks(
|
||||
"Alas<styled>Awesome</styled>\n<style>foo</style> Trendy!",
|
||||
"Alas<styled>Awesome</styled>\n Trendy!",
|
||||
array('foo')
|
||||
);
|
||||
}
|
||||
|
||||
function assertCleanCSS($input, $expect = true) {
|
||||
$filter = new HTMLPurifier_Filter_ExtractStyleBlocks();
|
||||
if ($expect === true) $expect = $input;
|
||||
$this->normalize($input);
|
||||
$this->normalize($expect);
|
||||
$result = $filter->cleanCSS($input, $this->config, $this->context);
|
||||
$this->assertIdentical($result, $expect);
|
||||
}
|
||||
|
||||
function test_cleanCSS_malformed() {
|
||||
$this->assertCleanCSS('</style>', '');
|
||||
}
|
||||
|
||||
function test_cleanCSS_selector() {
|
||||
$this->assertCleanCSS("a .foo #id div.cl#foo {\nfont-weight:700;\n}");
|
||||
}
|
||||
|
||||
function test_cleanCSS_angledBrackets() {
|
||||
$this->assertCleanCSS(
|
||||
".class {\nfont-family:'</style>';\n}",
|
||||
".class {\nfont-family:'\\3C /style\\3E ';\n}"
|
||||
);
|
||||
}
|
||||
|
||||
function test_cleanCSS_angledBrackets2() {
|
||||
// CSSTidy's behavior in this case is wrong, and should be fixed
|
||||
//$this->assertCleanCSS(
|
||||
// "span[title=\"</style>\"] {\nfont-size:12pt;\n}",
|
||||
// "span[title=\"\\3C /style\\3E \"] {\nfont-size:12pt;\n}"
|
||||
//);
|
||||
}
|
||||
|
||||
function test_cleanCSS_bogus() {
|
||||
$this->assertCleanCSS("div {bogus:tree;}", "div {\n}");
|
||||
}
|
||||
|
||||
function test_cleanCSS_escapeCodes() {
|
||||
$this->assertCleanCSS(
|
||||
".class {\nfont-family:'\\3C /style\\3E ';\n}"
|
||||
);
|
||||
}
|
||||
|
||||
function test_cleanCSS_noEscapeCodes() {
|
||||
$this->config->set('Filter', 'ExtractStyleBlocksEscaping', false);
|
||||
$this->assertCleanCSS(
|
||||
".class {\nfont-family:'</style>';\n}"
|
||||
);
|
||||
}
|
||||
|
||||
function test_cleanCSS_scope() {
|
||||
$this->config->set('Filter', 'ExtractStyleBlocksScope', '#foo');
|
||||
$this->assertCleanCSS(
|
||||
"p {\ntext-indent:1em;\n}",
|
||||
"#foo p {\ntext-indent:1em;\n}"
|
||||
);
|
||||
}
|
||||
|
||||
function test_cleanCSS_scopeWithSelectorCommas() {
|
||||
$this->config->set('Filter', 'ExtractStyleBlocksScope', '#foo');
|
||||
$this->assertCleanCSS(
|
||||
"b, i {\ntext-decoration:underline;\n}",
|
||||
"#foo b, #foo i {\ntext-decoration:underline;\n}"
|
||||
);
|
||||
}
|
||||
|
||||
function test_cleanCSS_scopeWithNaughtySelector() {
|
||||
$this->config->set('Filter', 'ExtractStyleBlocksScope', '#foo');
|
||||
$this->assertCleanCSS(" + p {\ntext-indent:1em;\n}", '');
|
||||
}
|
||||
|
||||
function test_cleanCSS_scopeWithMultipleNaughtySelectors() {
|
||||
$this->config->set('Filter', 'ExtractStyleBlocksScope', '#foo');
|
||||
$this->assertCleanCSS(" ++ ++ p {\ntext-indent:1em;\n}", '');
|
||||
}
|
||||
|
||||
function test_cleanCSS_scopeWithCommas() {
|
||||
$this->config->set('Filter', 'ExtractStyleBlocksScope', '#foo, .bar');
|
||||
$this->assertCleanCSS(
|
||||
"p {\ntext-indent:1em;\n}",
|
||||
"#foo p, .bar p {\ntext-indent:1em;\n}"
|
||||
);
|
||||
}
|
||||
|
||||
function test_cleanCSS_scopeAllWithCommas() {
|
||||
$this->config->set('Filter', 'ExtractStyleBlocksScope', '#foo, .bar');
|
||||
$this->assertCleanCSS(
|
||||
"p, div {\ntext-indent:1em;\n}",
|
||||
"#foo p, #foo div, .bar p, .bar div {\ntext-indent:1em;\n}"
|
||||
);
|
||||
}
|
||||
|
||||
function test_cleanCSS_scopeWithConflicts() {
|
||||
$this->config->set('Filter', 'ExtractStyleBlocksScope', 'p');
|
||||
$this->assertCleanCSS(
|
||||
"div {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
p div {
|
||||
text-align:left;
|
||||
}",
|
||||
|
||||
"p div {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
p p div {
|
||||
text-align:left;
|
||||
}"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/Generator.php';
|
||||
require_once 'HTMLPurifier/EntityLookup.php';
|
||||
|
||||
require_once 'HTMLPurifier/ComplexHarness.php';
|
||||
|
||||
class HTMLPurifier_GeneratorTest extends HTMLPurifier_ComplexHarness
|
||||
{
|
||||
|
||||
protected $gen;
|
||||
protected $_entity_lookup;
|
||||
protected $config;
|
||||
|
||||
function HTMLPurifier_GeneratorTest() {
|
||||
$this->HTMLPurifier_Harness();
|
||||
$this->gen = new HTMLPurifier_Generator();
|
||||
$this->_entity_lookup = HTMLPurifier_EntityLookup::instance();
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->obj = new HTMLPurifier_Generator();
|
||||
$this->func = null;
|
||||
$this->to_tokens = false;
|
||||
$this->to_html = false;
|
||||
}
|
||||
|
||||
function test_generateFromToken() {
|
||||
|
||||
$inputs = $expect = array();
|
||||
|
||||
$inputs[0] = new HTMLPurifier_Token_Text('Foobar.<>');
|
||||
$expect[0] = 'Foobar.<>';
|
||||
|
||||
$inputs[1] = new HTMLPurifier_Token_Start('a',
|
||||
array('href' => 'dyn?a=foo&b=bar')
|
||||
);
|
||||
$expect[1] = '<a href="dyn?a=foo&b=bar">';
|
||||
|
||||
$inputs[2] = new HTMLPurifier_Token_End('b');
|
||||
$expect[2] = '</b>';
|
||||
|
||||
$inputs[3] = new HTMLPurifier_Token_Empty('br',
|
||||
array('style' => 'font-family:"Courier New";')
|
||||
);
|
||||
$expect[3] = '<br style="font-family:"Courier New";" />';
|
||||
|
||||
$inputs[4] = new HTMLPurifier_Token_Start('asdf');
|
||||
$expect[4] = '<asdf>';
|
||||
|
||||
$inputs[5] = new HTMLPurifier_Token_Empty('br');
|
||||
$expect[5] = '<br />';
|
||||
|
||||
// test fault tolerance
|
||||
$inputs[6] = null;
|
||||
$expect[6] = '';
|
||||
|
||||
// don't convert non-special characters
|
||||
$theta_char = $this->_entity_lookup->table['theta'];
|
||||
$inputs[7] = new HTMLPurifier_Token_Text($theta_char);
|
||||
$expect[7] = $theta_char;
|
||||
|
||||
foreach ($inputs as $i => $input) {
|
||||
$result = $this->obj->generateFromToken($input);
|
||||
$this->assertIdentical($result, $expect[$i]);
|
||||
paintIf($result, $result != $expect[$i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function test_generateAttributes() {
|
||||
|
||||
$inputs = $expect = array();
|
||||
|
||||
$inputs[0] = array();
|
||||
$expect[0] = '';
|
||||
|
||||
$inputs[1] = array('href' => 'dyn?a=foo&b=bar');
|
||||
$expect[1] = 'href="dyn?a=foo&b=bar"';
|
||||
|
||||
$inputs[2] = array('style' => 'font-family:"Courier New";');
|
||||
$expect[2] = 'style="font-family:"Courier New";"';
|
||||
|
||||
$inputs[3] = array('src' => 'picture.jpg', 'alt' => 'Short & interesting');
|
||||
$expect[3] = 'src="picture.jpg" alt="Short & interesting"';
|
||||
|
||||
// don't escape nonspecial characters
|
||||
$theta_char = $this->_entity_lookup->table['theta'];
|
||||
$inputs[4] = array('title' => 'Theta is ' . $theta_char);
|
||||
$expect[4] = 'title="Theta is ' . $theta_char . '"';
|
||||
|
||||
foreach ($inputs as $i => $input) {
|
||||
$result = $this->obj->generateAttributes($input, 'irrelevant');
|
||||
$this->assertIdentical($result, $expect[$i]);
|
||||
paintIf($result, $result != $expect[$i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function test_generateAttributes_minimized() {
|
||||
$gen = new HTMLPurifier_Generator();
|
||||
$context = new HTMLPurifier_Context();
|
||||
$gen->generateFromTokens(array(), HTMLPurifier_Config::create(array('HTML.Doctype' => 'HTML 4.01 Transitional')), $context);
|
||||
$result = $gen->generateAttributes(array('compact' => 'compact'), 'menu');
|
||||
$this->assertIdentical($result, 'compact');
|
||||
}
|
||||
|
||||
function test_generateFromTokens() {
|
||||
|
||||
$this->func = 'generateFromTokens';
|
||||
|
||||
$this->assertResult(
|
||||
array(
|
||||
new HTMLPurifier_Token_Start('b'),
|
||||
new HTMLPurifier_Token_Text('Foobar!'),
|
||||
new HTMLPurifier_Token_End('b')
|
||||
),
|
||||
'<b>Foobar!</b>'
|
||||
);
|
||||
|
||||
$this->assertResult(array(), '');
|
||||
|
||||
}
|
||||
|
||||
function assertGeneration($tokens, $expect) {
|
||||
$context = new HTMLPurifier_Context();
|
||||
$result = $this->gen->generateFromTokens(
|
||||
$tokens, $this->config, $context);
|
||||
// normalized newlines, this probably should be put somewhere else
|
||||
$result = str_replace("\r\n", "\n", $result);
|
||||
$result = str_replace("\r", "\n", $result);
|
||||
$this->assertIdentical($expect, $result);
|
||||
}
|
||||
|
||||
function test_generateFromTokens_Scripting() {
|
||||
$this->config = HTMLPurifier_Config::createDefault();
|
||||
|
||||
$this->assertGeneration(
|
||||
array(
|
||||
new HTMLPurifier_Token_Start('script'),
|
||||
new HTMLPurifier_Token_Text('alert(3 < 5);'),
|
||||
new HTMLPurifier_Token_End('script')
|
||||
),
|
||||
"<script><!--//--><![CDATA[//><!--\nalert(3 < 5);\n//--><!]]></script>"
|
||||
);
|
||||
|
||||
// if missing close tag, don't do anything
|
||||
$this->assertGeneration(
|
||||
array(
|
||||
new HTMLPurifier_Token_Start('script'),
|
||||
new HTMLPurifier_Token_Text('alert(3 < 5);'),
|
||||
),
|
||||
"<script>alert(3 < 5);"
|
||||
);
|
||||
|
||||
// if two script blocks, don't do anything
|
||||
$this->assertGeneration(
|
||||
array(
|
||||
new HTMLPurifier_Token_Start('script'),
|
||||
new HTMLPurifier_Token_Text('alert(3 < 5);'),
|
||||
new HTMLPurifier_Token_Text('foo();'),
|
||||
new HTMLPurifier_Token_End('script')
|
||||
),
|
||||
"<script>alert(3 < 5);foo();</script>"
|
||||
);
|
||||
|
||||
|
||||
|
||||
$this->config = HTMLPurifier_Config::createDefault();
|
||||
$this->config->set('Core', 'CommentScriptContents', false);
|
||||
|
||||
$this->assertGeneration(
|
||||
array(
|
||||
new HTMLPurifier_Token_Start('script'),
|
||||
new HTMLPurifier_Token_Text('alert(3 < 5);'),
|
||||
new HTMLPurifier_Token_End('script')
|
||||
),
|
||||
"<script>alert(3 < 5);</script>"
|
||||
);
|
||||
}
|
||||
|
||||
function test_generateFromTokens_XHTMLoff() {
|
||||
$this->config = HTMLPurifier_Config::createDefault();
|
||||
$this->config->set('Core', 'XHTML', false);
|
||||
|
||||
// omit trailing slash
|
||||
$this->assertGeneration(
|
||||
array( new HTMLPurifier_Token_Empty('br') ),
|
||||
'<br>'
|
||||
);
|
||||
|
||||
// there should be a test for attribute minimization, but it is
|
||||
// impossible for something like that to happen due to our current
|
||||
// definitions! fix it later
|
||||
|
||||
// namespaced attributes must be dropped
|
||||
$this->assertGeneration(
|
||||
array( new HTMLPurifier_Token_Start('p', array('xml:lang'=>'fr')) ),
|
||||
'<p>'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_generateFromTokens_TidyFormat() {
|
||||
// abort test if tidy isn't loaded
|
||||
if (!extension_loaded('tidy')) return;
|
||||
|
||||
$this->config = HTMLPurifier_Config::createDefault();
|
||||
$this->config->set('Core', 'TidyFormat', true);
|
||||
$this->config->set('Output', 'Newline', "\n");
|
||||
|
||||
// nice wrapping please
|
||||
$this->assertGeneration(
|
||||
array(
|
||||
new HTMLPurifier_Token_Start('div'),
|
||||
new HTMLPurifier_Token_Text('Text'),
|
||||
new HTMLPurifier_Token_End('div')
|
||||
),
|
||||
"<div>\n Text\n</div>\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLDefinition.php';
|
||||
|
||||
class HTMLPurifier_HTMLDefinitionTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_parseTinyMCEAllowedList() {
|
||||
|
||||
$def = new HTMLPurifier_HTMLDefinition();
|
||||
|
||||
// note: this is case-sensitive, but its config schema
|
||||
// counterpart is not. This is generally a good thing for users,
|
||||
// but it's a slight internal inconsistency
|
||||
|
||||
$this->assertEqual(
|
||||
$def->parseTinyMCEAllowedList(''),
|
||||
array(array(), array())
|
||||
);
|
||||
|
||||
$this->assertEqual(
|
||||
$def->parseTinyMCEAllowedList('a,b,c'),
|
||||
array(array('a' => true, 'b' => true, 'c' => true), array())
|
||||
);
|
||||
|
||||
$this->assertEqual(
|
||||
$def->parseTinyMCEAllowedList('a[x|y|z]'),
|
||||
array(array('a' => true), array('a.x' => true, 'a.y' => true, 'a.z' => true))
|
||||
);
|
||||
|
||||
$this->assertEqual(
|
||||
$def->parseTinyMCEAllowedList('*[id]'),
|
||||
array(array(), array('*.id' => true))
|
||||
);
|
||||
|
||||
$this->assertEqual(
|
||||
$def->parseTinyMCEAllowedList('a[*]'),
|
||||
array(array('a' => true), array('a.*' => true))
|
||||
);
|
||||
|
||||
$this->assertEqual(
|
||||
$def->parseTinyMCEAllowedList('span[style],strong,a[href|title]'),
|
||||
array(array('span' => true, 'strong' => true, 'a' => true),
|
||||
array('span.style' => true, 'a.href' => true, 'a.title' => true))
|
||||
);
|
||||
|
||||
$this->assertEqual(
|
||||
// alternate form:
|
||||
$def->parseTinyMCEAllowedList(
|
||||
'span[style]
|
||||
strong
|
||||
a[href|title]
|
||||
'),
|
||||
array(array('span' => true, 'strong' => true, 'a' => true),
|
||||
array('span.style' => true, 'a.href' => true, 'a.title' => true))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_Allowed() {
|
||||
|
||||
$config1 = HTMLPurifier_Config::create(array(
|
||||
'HTML.AllowedElements' => array('b', 'i', 'p', 'a'),
|
||||
'HTML.AllowedAttributes' => array('a.href', '*.id')
|
||||
));
|
||||
|
||||
$config2 = HTMLPurifier_Config::create(array(
|
||||
'HTML.Allowed' => 'b,i,p,a[href],*[id]'
|
||||
));
|
||||
|
||||
$this->assertEqual($config1->getHTMLDefinition(), $config2->getHTMLDefinition());
|
||||
|
||||
}
|
||||
|
||||
function test_addAttribute() {
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.DefinitionID' => 'HTMLPurifier_HTMLDefinitionTest->test_addAttribute'
|
||||
));
|
||||
$def =& $config->getHTMLDefinition(true);
|
||||
$def->addAttribute('span', 'custom', 'Enum#attribute');
|
||||
|
||||
$purifier = new HTMLPurifier($config);
|
||||
$input = '<span custom="attribute">Custom!</span>';
|
||||
$output = $purifier->purify($input);
|
||||
$this->assertIdentical($input, $output);
|
||||
|
||||
}
|
||||
|
||||
function test_addElement() {
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.DefinitionID' => 'HTMLPurifier_HTMLDefinitionTest->test_addElement'
|
||||
));
|
||||
$def =& $config->getHTMLDefinition(true);
|
||||
$def->addElement('marquee', 'Inline', 'Inline', 'Common', array('width' => 'Length'));
|
||||
|
||||
$purifier = new HTMLPurifier($config);
|
||||
$input = '<span><marquee width="50">Foobar</marquee></span>';
|
||||
$output = $purifier->purify($input);
|
||||
$this->assertIdentical($input, $output);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModuleHarness.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_ObjectTest extends HTMLPurifier_HTMLModuleHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->config->set('HTML', 'Trusted', true);
|
||||
}
|
||||
|
||||
function testDefaultRemoval() {
|
||||
$this->config->set('HTML', 'Trusted', false);
|
||||
$this->assertResult(
|
||||
'<object></object>', ''
|
||||
);
|
||||
}
|
||||
|
||||
function testMinimal() {
|
||||
$this->assertResult('<object></object>');
|
||||
}
|
||||
|
||||
function testStandardUseCase() {
|
||||
$this->assertResult(
|
||||
'<object type="video/x-ms-wmv" data="http://domain.com/video.wmv" width="320" height="256">
|
||||
<param name="src" value="http://domain.com/video.wmv" />
|
||||
<param name="autostart" value="false" />
|
||||
<param name="controller" value="true" />
|
||||
<param name="pluginurl" value="http://www.microsoft.com/Windows/MediaPlayer/" />
|
||||
<a href="http://www.microsoft.com/Windows/MediaPlayer/">Windows Media player required</a>
|
||||
</object>'
|
||||
);
|
||||
}
|
||||
|
||||
// more test-cases?
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModuleHarness.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_RubyTest extends HTMLPurifier_HTMLModuleHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->config->set('HTML', 'Doctype', 'XHTML 1.1');
|
||||
}
|
||||
|
||||
function testBasicUse() {
|
||||
$this->assertResult(
|
||||
'<ruby><rb>WWW</rb><rt>World Wide Web</rt></ruby>'
|
||||
);
|
||||
}
|
||||
|
||||
function testRPUse() {
|
||||
$this->assertResult(
|
||||
'<ruby><rb>WWW</rb><rp>(</rp><rt>World Wide Web</rt><rp>)</rp></ruby>'
|
||||
);
|
||||
}
|
||||
|
||||
function testComplexUse() {
|
||||
$this->assertResult(
|
||||
'<ruby>
|
||||
<rbc>
|
||||
<rb>10</rb>
|
||||
<rb>31</rb>
|
||||
<rb>2002</rb>
|
||||
</rbc>
|
||||
<rtc>
|
||||
<rt>Month</rt>
|
||||
<rt>Day</rt>
|
||||
<rt>Year</rt>
|
||||
</rtc>
|
||||
<rtc>
|
||||
<rt rbspan="3">Expiration Date</rt>
|
||||
</rtc>
|
||||
</ruby>'
|
||||
);
|
||||
|
||||
/* not implemented
|
||||
function testBackwardsCompat() {
|
||||
$this->assertResult(
|
||||
'<ruby>A<rp>(</rp><rt>aaa</rt><rp>)</rp></ruby>',
|
||||
'<ruby><rb>A</rb><rp>(</rp><rt>aaa</rt><rp>)</rp></ruby>'
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModuleHarness.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_ScriptingTest extends HTMLPurifier_HTMLModuleHarness
|
||||
{
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->config->set('HTML', 'Trusted', true);
|
||||
$this->config->set('Core', 'CommentScriptContents', false);
|
||||
}
|
||||
|
||||
function testDefaultRemoval() {
|
||||
$this->config->set('HTML', 'Trusted', false);
|
||||
$this->assertResult(
|
||||
'<script type="text/javascript">foo();</script>', ''
|
||||
);
|
||||
}
|
||||
|
||||
function testPreserve() {
|
||||
$this->assertResult(
|
||||
'<script type="text/javascript">foo();</script>'
|
||||
);
|
||||
}
|
||||
|
||||
function testCDATAEnclosure() {
|
||||
$this->assertResult(
|
||||
'<script type="text/javascript">//<![CDATA[
|
||||
alert("<This is compatible with XHTML>");
|
||||
//]]></script>'
|
||||
);
|
||||
}
|
||||
|
||||
function testAllAttributes() {
|
||||
$this->assertResult(
|
||||
'<script
|
||||
defer="defer"
|
||||
src="test.js"
|
||||
type="text/javascript"
|
||||
>PCDATA</script>'
|
||||
);
|
||||
}
|
||||
|
||||
function testUnsupportedAttributes() {
|
||||
$this->assertResult(
|
||||
'<script
|
||||
type="text/javascript"
|
||||
charset="utf-8"
|
||||
>PCDATA</script>',
|
||||
'<script type="text/javascript">PCDATA</script>'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule/Tidy.php';
|
||||
|
||||
Mock::generatePartial(
|
||||
'HTMLPurifier_HTMLModule_Tidy',
|
||||
'HTMLPurifier_HTMLModule_Tidy_TestForConstruct',
|
||||
array('makeFixes', 'makeFixesForLevel', 'populate')
|
||||
);
|
||||
|
||||
class HTMLPurifier_HTMLModule_TidyTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_getFixesForLevel() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule_Tidy();
|
||||
$module->fixesForLevel['light'][] = 'light-fix';
|
||||
$module->fixesForLevel['medium'][] = 'medium-fix';
|
||||
$module->fixesForLevel['heavy'][] = 'heavy-fix';
|
||||
|
||||
$this->assertIdentical(
|
||||
array(),
|
||||
$module->getFixesForLevel('none')
|
||||
);
|
||||
$this->assertIdentical(
|
||||
array('light-fix' => true),
|
||||
$module->getFixesForLevel('light')
|
||||
);
|
||||
$this->assertIdentical(
|
||||
array('light-fix' => true, 'medium-fix' => true),
|
||||
$module->getFixesForLevel('medium')
|
||||
);
|
||||
$this->assertIdentical(
|
||||
array('light-fix' => true, 'medium-fix' => true, 'heavy-fix' => true),
|
||||
$module->getFixesForLevel('heavy')
|
||||
);
|
||||
|
||||
$this->expectError('Tidy level turbo not recognized');
|
||||
$module->getFixesForLevel('turbo');
|
||||
|
||||
}
|
||||
|
||||
function test_construct() {
|
||||
|
||||
$i = 0; // counter, helps us isolate expectations
|
||||
|
||||
// initialize partial mock
|
||||
$module = new HTMLPurifier_HTMLModule_Tidy_TestForConstruct();
|
||||
$module->fixesForLevel['light'] = array('light-fix-1', 'light-fix-2');
|
||||
$module->fixesForLevel['medium'] = array('medium-fix-1', 'medium-fix-2');
|
||||
$module->fixesForLevel['heavy'] = array('heavy-fix-1', 'heavy-fix-2');
|
||||
|
||||
$j = 0;
|
||||
$fixes = array(
|
||||
'light-fix-1' => $lf1 = $j++,
|
||||
'light-fix-2' => $lf2 = $j++,
|
||||
'medium-fix-1' => $mf1 = $j++,
|
||||
'medium-fix-2' => $mf2 = $j++,
|
||||
'heavy-fix-1' => $hf1 = $j++,
|
||||
'heavy-fix-2' => $hf2 = $j++
|
||||
);
|
||||
$module->setReturnValue('makeFixes', $fixes);
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.TidyLevel' => 'none'
|
||||
));
|
||||
$module->expectAt($i++, 'populate', array(array()));
|
||||
$module->construct($config);
|
||||
|
||||
// basic levels
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.TidyLevel' => 'light'
|
||||
));
|
||||
$module->expectAt($i++, 'populate', array(array(
|
||||
'light-fix-1' => $lf1,
|
||||
'light-fix-2' => $lf2
|
||||
)));
|
||||
$module->construct($config);
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.TidyLevel' => 'heavy'
|
||||
));
|
||||
$module->expectAt($i++, 'populate', array(array(
|
||||
'light-fix-1' => $lf1,
|
||||
'light-fix-2' => $lf2,
|
||||
'medium-fix-1' => $mf1,
|
||||
'medium-fix-2' => $mf2,
|
||||
'heavy-fix-1' => $hf1,
|
||||
'heavy-fix-2' => $hf2
|
||||
)));
|
||||
$module->construct($config);
|
||||
|
||||
// fine grained tuning
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.TidyLevel' => 'none',
|
||||
'HTML.TidyAdd' => array('light-fix-1', 'medium-fix-1')
|
||||
));
|
||||
$module->expectAt($i++, 'populate', array(array(
|
||||
'light-fix-1' => $lf1,
|
||||
'medium-fix-1' => $mf1
|
||||
)));
|
||||
$module->construct($config);
|
||||
|
||||
$config = HTMLPurifier_Config::create(array(
|
||||
'HTML.TidyLevel' => 'medium',
|
||||
'HTML.TidyRemove' => array('light-fix-1', 'medium-fix-1')
|
||||
));
|
||||
$module->expectAt($i++, 'populate', array(array(
|
||||
'light-fix-2' => $lf2,
|
||||
'medium-fix-2' => $mf2
|
||||
)));
|
||||
$module->construct($config);
|
||||
|
||||
// done
|
||||
|
||||
$module->tally();
|
||||
|
||||
}
|
||||
|
||||
function test_makeFixesForLevel() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule_Tidy();
|
||||
$module->defaultLevel = 'heavy';
|
||||
|
||||
$module->makeFixesForLevel(array(
|
||||
'fix-1' => 0,
|
||||
'fix-2' => 1,
|
||||
'fix-3' => 2
|
||||
));
|
||||
|
||||
$this->assertIdentical($module->fixesForLevel['heavy'], array('fix-1', 'fix-2', 'fix-3'));
|
||||
$this->assertIdentical($module->fixesForLevel['medium'], array());
|
||||
$this->assertIdentical($module->fixesForLevel['light'], array());
|
||||
|
||||
}
|
||||
function test_makeFixesForLevel_undefinedLevel() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule_Tidy();
|
||||
$module->defaultLevel = 'bananas';
|
||||
|
||||
$this->expectError('Default level bananas does not exist');
|
||||
|
||||
$module->makeFixesForLevel(array(
|
||||
'fix-1' => 0
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
function test_getFixType() {
|
||||
|
||||
// syntax needs documenting
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule_Tidy();
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->getFixType('a'),
|
||||
array('tag_transform', array('element' => 'a'))
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->getFixType('a@href'),
|
||||
$reuse = array('attr_transform_pre', array('element' => 'a', 'attr' => 'href'))
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->getFixType('a@href#pre'),
|
||||
$reuse
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->getFixType('a@href#post'),
|
||||
array('attr_transform_post', array('element' => 'a', 'attr' => 'href'))
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->getFixType('xml:foo@xml:bar'),
|
||||
array('attr_transform_pre', array('element' => 'xml:foo', 'attr' => 'xml:bar'))
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->getFixType('blockquote#child'),
|
||||
array('child', array('element' => 'blockquote'))
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->getFixType('@lang'),
|
||||
array('attr_transform_pre', array('attr' => 'lang'))
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->getFixType('@lang#post'),
|
||||
array('attr_transform_post', array('attr' => 'lang'))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_populate() {
|
||||
|
||||
$i = 0;
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule_Tidy();
|
||||
$module->populate(array(
|
||||
'element' => $element = $i++,
|
||||
'element@attr' => $attr = $i++,
|
||||
'element@attr#post' => $attr_post = $i++,
|
||||
'element#child' => $child = $i++,
|
||||
'element#content_model_type' => $content_model_type = $i++,
|
||||
'@attr' => $global_attr = $i++,
|
||||
'@attr#post' => $global_attr_post = $i++
|
||||
));
|
||||
|
||||
$module2 = new HTMLPurifier_HTMLModule_Tidy();
|
||||
$e =& $module2->addBlankElement('element');
|
||||
$e->attr_transform_pre['attr'] = $attr;
|
||||
$e->attr_transform_post['attr'] = $attr_post;
|
||||
$e->child = $child;
|
||||
$e->content_model_type = $content_model_type;
|
||||
$module2->info_tag_transform['element'] = $element;
|
||||
$module2->info_attr_transform_pre['attr'] = $global_attr;
|
||||
$module2->info_attr_transform_post['attr'] = $global_attr_post;
|
||||
|
||||
$this->assertEqual($module, $module2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/StrategyHarness.php';
|
||||
require_once 'HTMLPurifier/Strategy/Core.php';
|
||||
|
||||
class HTMLPurifier_HTMLModuleHarness extends HTMLPurifier_StrategyHarness
|
||||
{
|
||||
function setup() {
|
||||
parent::setup();
|
||||
$this->obj = new HTMLPurifier_Strategy_Core();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModuleManager.php';
|
||||
|
||||
class HTMLPurifier_HTMLModuleManagerTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_addModule() {
|
||||
$manager = new HTMLPurifier_HTMLModuleManager();
|
||||
$manager->doctypes->register('Blank'); // doctype normally is blank...
|
||||
|
||||
$attrdef_nmtokens = new HTMLPurifier_AttrDef_HTML_Nmtokens();
|
||||
|
||||
generate_mock_once('HTMLPurifier_AttrDef');
|
||||
$attrdef = new HTMLPurifier_AttrDefMock();
|
||||
$attrdef->setReturnValue('make', $attrdef_nmtokens);
|
||||
$manager->attrTypes->info['NMTOKENS'] =& $attrdef;
|
||||
|
||||
// ...but we add user modules
|
||||
|
||||
$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);
|
||||
|
||||
$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);
|
||||
|
||||
$formatting_module = new HTMLPurifier_HTMLModule();
|
||||
$formatting_module->name = 'Formatting';
|
||||
$formatting_module->addElement('em', true, 'Inline', 'Inline', 'Common');
|
||||
$manager->addModule($formatting_module);
|
||||
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML', 'Trusted', false);
|
||||
$config->set('HTML', 'CustomDoctype', 'Blank');
|
||||
|
||||
$manager->setup($config);
|
||||
|
||||
$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;
|
||||
|
||||
$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->assertEqual(
|
||||
array('p' => $p, 'em' => $em),
|
||||
$manager->getElements()
|
||||
);
|
||||
|
||||
// test trusted parameter override
|
||||
|
||||
$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->assertEqual($div, $manager->getElement('div', true));
|
||||
|
||||
}
|
||||
|
||||
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.CustomDoctype' => 'Fantasy Inventory 1.0',
|
||||
'HTML.AllowedModules' => 'Weapons'
|
||||
));
|
||||
$manager->setup($config);
|
||||
|
||||
$this->assertTrue( isset($manager->modules['Weapons']));
|
||||
$this->assertFalse(isset($manager->modules['Magic']));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule.php';
|
||||
require_once 'HTMLPurifier/AttrDef.php';
|
||||
|
||||
class HTMLPurifier_HTMLModuleTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test_addElementToContentSet() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule();
|
||||
|
||||
$module->addElementToContentSet('b', 'Inline');
|
||||
$this->assertIdentical($module->content_sets, array('Inline' => 'b'));
|
||||
|
||||
$module->addElementToContentSet('i', 'Inline');
|
||||
$this->assertIdentical($module->content_sets, array('Inline' => 'b | i'));
|
||||
|
||||
}
|
||||
|
||||
function test_addElement() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule();
|
||||
$def =& $module->addElement(
|
||||
'a', true, 'Inline', 'Optional: #PCDATA', array('Common'),
|
||||
array(
|
||||
'href' => 'URI'
|
||||
)
|
||||
);
|
||||
|
||||
$module2 = new HTMLPurifier_HTMLModule();
|
||||
$def2 = new HTMLPurifier_ElementDef();
|
||||
$def2->safe = true;
|
||||
$def2->content_model = '#PCDATA';
|
||||
$def2->content_model_type = 'optional';
|
||||
$def2->attr = array(
|
||||
'href' => 'URI',
|
||||
0 => array('Common')
|
||||
);
|
||||
$module2->info['a'] = $def2;
|
||||
$module2->elements = array('a');
|
||||
$module2->content_sets['Inline'] = 'a';
|
||||
|
||||
$this->assertIdentical($module, $module2);
|
||||
$this->assertIdentical($def, $def2);
|
||||
$this->assertReference($def, $module->info['a']);
|
||||
|
||||
}
|
||||
|
||||
function test_parseContents() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule();
|
||||
|
||||
// pre-defined templates
|
||||
$this->assertIdentical(
|
||||
$module->parseContents('Inline'),
|
||||
array('optional', 'Inline | #PCDATA')
|
||||
);
|
||||
$this->assertIdentical(
|
||||
$module->parseContents('Flow'),
|
||||
array('optional', 'Flow | #PCDATA')
|
||||
);
|
||||
$this->assertIdentical(
|
||||
$module->parseContents('Empty'),
|
||||
array('empty', '')
|
||||
);
|
||||
|
||||
// normalization procedures
|
||||
$this->assertIdentical(
|
||||
$module->parseContents('optional: a'),
|
||||
array('optional', 'a')
|
||||
);
|
||||
$this->assertIdentical(
|
||||
$module->parseContents('OPTIONAL :a'),
|
||||
array('optional', 'a')
|
||||
);
|
||||
$this->assertIdentical(
|
||||
$module->parseContents('Optional: a'),
|
||||
array('optional', 'a')
|
||||
);
|
||||
|
||||
// others
|
||||
$this->assertIdentical(
|
||||
$module->parseContents('Optional: a | b | c'),
|
||||
array('optional', 'a | b | c')
|
||||
);
|
||||
|
||||
// object pass-through
|
||||
generate_mock_once('HTMLPurifier_AttrDef');
|
||||
$this->assertIdentical(
|
||||
$module->parseContents(new HTMLPurifier_AttrDefMock()),
|
||||
array(null, null)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_mergeInAttrIncludes() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule();
|
||||
|
||||
$attr = array();
|
||||
$module->mergeInAttrIncludes($attr, 'Common');
|
||||
$this->assertIdentical($attr, array(0 => array('Common')));
|
||||
|
||||
$attr = array('a' => 'b');
|
||||
$module->mergeInAttrIncludes($attr, array('Common', 'Good'));
|
||||
$this->assertIdentical($attr, array('a' => 'b', 0 => array('Common', 'Good')));
|
||||
|
||||
}
|
||||
|
||||
function test_addBlankElement() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule();
|
||||
$def =& $module->addBlankElement('a');
|
||||
|
||||
$def2 = new HTMLPurifier_ElementDef();
|
||||
$def2->standalone = false;
|
||||
|
||||
$this->assertReference($module->info['a'], $def);
|
||||
$this->assertIdentical($def, $def2);
|
||||
|
||||
}
|
||||
|
||||
function test_makeLookup() {
|
||||
|
||||
$module = new HTMLPurifier_HTMLModule();
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->makeLookup('foo'),
|
||||
array('foo' => true)
|
||||
);
|
||||
$this->assertIdentical(
|
||||
$module->makeLookup(array('foo')),
|
||||
array('foo' => true)
|
||||
);
|
||||
|
||||
$this->assertIdentical(
|
||||
$module->makeLookup('foo', 'two'),
|
||||
array('foo' => true, 'two' => true)
|
||||
);
|
||||
$this->assertIdentical(
|
||||
$module->makeLookup(array('foo', 'two')),
|
||||
array('foo' => true, 'two' => true)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/URIParser.php';
|
||||
|
||||
/**
|
||||
* All-use harness, use this rather than SimpleTest's
|
||||
*/
|
||||
class HTMLPurifier_Harness extends UnitTestCase
|
||||
{
|
||||
|
||||
function HTMLPurifier_Harness() {
|
||||
parent::UnitTestCase();
|
||||
}
|
||||
|
||||
protected $config, $context;
|
||||
|
||||
/**
|
||||
* Generates easily accessible default config/context
|
||||
*/
|
||||
function setUp() {
|
||||
list($this->config, $this->context) = $this->createCommon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts config and context and prepares them into a valid state
|
||||
* @param &$config Reference to config variable
|
||||
* @param &$context Reference to context variable
|
||||
*/
|
||||
function prepareCommon(&$config, &$context) {
|
||||
$config = HTMLPurifier_Config::create($config);
|
||||
if (!$context) $context = new HTMLPurifier_Context();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates default configuration and context objects
|
||||
* @return Defaults in form of array($config, $context)
|
||||
*/
|
||||
function createCommon() {
|
||||
return array(HTMLPurifier_Config::createDefault(), new HTMLPurifier_Context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a string to Unix (\n) endings
|
||||
*/
|
||||
function normalize(&$string) {
|
||||
$string = str_replace(array("\r\n", "\r"), "\n", $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* If $expect is false, ignore $result and check if status failed.
|
||||
* Otherwise, check if $status if true and $result === $expect.
|
||||
* @param $status Boolean status
|
||||
* @param $result Mixed result from processing
|
||||
* @param $expect Mixed expectation for result
|
||||
*/
|
||||
function assertEitherFailOrIdentical($status, $result, $expect) {
|
||||
if ($expect === false) {
|
||||
$this->assertFalse($status, 'Expected false result, got true');
|
||||
} else {
|
||||
$this->assertTrue($status, 'Expected true result, got false');
|
||||
$this->assertIdentical($result, $expect);
|
||||
}
|
||||
}
|
||||
|
||||
function getTests() {
|
||||
// __onlytest makes only one test get triggered
|
||||
foreach (get_class_methods(get_class($this)) as $method) {
|
||||
if (strtolower(substr($method, 0, 10)) == '__onlytest') {
|
||||
return array($method);
|
||||
}
|
||||
}
|
||||
return parent::getTests();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/IDAccumulator.php';
|
||||
|
||||
class HTMLPurifier_IDAccumulatorTest extends HTMLPurifier_Harness
|
||||
{
|
||||
|
||||
function test() {
|
||||
|
||||
// initialize the accumulator
|
||||
$accumulator = new HTMLPurifier_IDAccumulator();
|
||||
|
||||
$this->assertTrue( $accumulator->add('id1'));
|
||||
$this->assertTrue( $accumulator->add('id2'));
|
||||
$this->assertFalse($accumulator->add('id1')); // repeated id
|
||||
|
||||
// you can also access the properties (they're public)
|
||||
$this->assertTrue( isset($accumulator->ids['id2']) );
|
||||
|
||||
}
|
||||
|
||||
function testLoad() {
|
||||
|
||||
$accumulator = new HTMLPurifier_IDAccumulator();
|
||||
|
||||
$accumulator->load(array('id1', 'id2', 'id3'));
|
||||
|
||||
$this->assertFalse($accumulator->add('id1')); // repeated id
|
||||
$this->assertTrue($accumulator->add('id4'));
|
||||
|
||||
}
|
||||
|
||||
function testBuild() {
|
||||
$this->config->set('Attr', 'IDBlacklist', array('foo'));
|
||||
$accumulator = HTMLPurifier_IDAccumulator::build($this->config, $this->context);
|
||||
$this->assertTrue( isset($accumulator->ids['foo']) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/InjectorHarness.php';
|
||||
require_once 'HTMLPurifier/Injector/AutoParagraph.php';
|
||||
|
||||
class HTMLPurifier_Injector_AutoParagraphTest extends HTMLPurifier_InjectorHarness
|
||||
{
|
||||
|
||||
function setup() {
|
||||
parent::setup();
|
||||
$this->config->set('AutoFormat', 'AutoParagraph', true);
|
||||
}
|
||||
|
||||
function testSingleParagraph() {
|
||||
$this->assertResult(
|
||||
'Foobar',
|
||||
'<p>Foobar</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testSingleMultiLineParagraph() {
|
||||
$this->assertResult(
|
||||
'Par 1
|
||||
Par 1 still',
|
||||
'<p>Par 1
|
||||
Par 1 still</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testTwoParagraphs() {
|
||||
$this->assertResult(
|
||||
'Par1
|
||||
|
||||
Par2',
|
||||
'<p>Par1</p><p>Par2</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testTwoParagraphsWithLotsOfSpace() {
|
||||
$this->assertResult(
|
||||
'Par1
|
||||
|
||||
|
||||
|
||||
Par2',
|
||||
'<p>Par1</p><p>Par2</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testTwoParagraphsWithInlineElements() {
|
||||
$this->assertResult(
|
||||
'<b>Par1</b>
|
||||
|
||||
<i>Par2</i>',
|
||||
'<p><b>Par1</b></p><p><i>Par2</i></p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testSingleParagraphThatLooksLikeTwo() {
|
||||
$this->assertResult(
|
||||
'<b>Par1
|
||||
|
||||
Par2</b>',
|
||||
'<p><b>Par1
|
||||
|
||||
Par2</b></p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testAddParagraphAdjacentToParagraph() {
|
||||
$this->assertResult(
|
||||
'Par1<p>Par2</p>',
|
||||
'<p>Par1</p><p>Par2</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testParagraphUnclosedInlineElement() {
|
||||
$this->assertResult(
|
||||
'<b>Par1',
|
||||
'<p><b>Par1</b></p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testPreservePreTags() {
|
||||
$this->assertResult(
|
||||
'<pre>Par1
|
||||
|
||||
Par1</pre>'
|
||||
);
|
||||
}
|
||||
|
||||
function testIgnoreTrailingWhitespace() {
|
||||
$this->assertResult(
|
||||
'Par1
|
||||
|
||||
',
|
||||
'<p>Par1</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testDoNotParagraphBlockElements() {
|
||||
$this->assertResult(
|
||||
'Par1
|
||||
|
||||
<div>Par2</div>
|
||||
|
||||
Par3',
|
||||
'<p>Par1</p><div>Par2</div><p>Par3</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testParagraphTextAndInlineNodes() {
|
||||
$this->assertResult(
|
||||
'Par<b>1</b>',
|
||||
'<p>Par<b>1</b></p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testIgnoreLeadingWhitespace() {
|
||||
$this->assertResult(
|
||||
'
|
||||
|
||||
Par',
|
||||
'<p>Par</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testIgnoreSurroundingWhitespace() {
|
||||
$this->assertResult(
|
||||
'
|
||||
|
||||
Par
|
||||
|
||||
',
|
||||
'<p>Par</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testParagraphInsideBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div>Par1
|
||||
|
||||
Par2</div>',
|
||||
'<div><p>Par1</p><p>Par2</p></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testParagraphInlineNodeInsideBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div><b>Par1</b>
|
||||
|
||||
Par2</div>',
|
||||
'<div><p><b>Par1</b></p><p>Par2</p></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testNoParagraphWhenOnlyOneInsideBlockNode() {
|
||||
$this->assertResult('<div>Par1</div>');
|
||||
}
|
||||
|
||||
function testParagraphTwoInlineNodesInsideBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div><b>Par1</b>
|
||||
|
||||
<i>Par2</i></div>',
|
||||
'<div><p><b>Par1</b></p><p><i>Par2</i></p></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testPreserveInlineNodesInPreTag() {
|
||||
$this->assertResult(
|
||||
'<pre><b>Par1</b>
|
||||
|
||||
<i>Par2</i></pre>'
|
||||
);
|
||||
}
|
||||
|
||||
function testSplitUpInternalsOfPTagInBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div><p>Foo
|
||||
|
||||
Bar</p></div>',
|
||||
'<div><p>Foo</p><p>Bar</p></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testSplitUpInlineNodesInPTagInBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div><p><b>Foo</b>
|
||||
|
||||
<i>Bar</i></p></div>',
|
||||
'<div><p><b>Foo</b></p><p><i>Bar</i></p></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testNoParagraphSingleInlineNodeInBlockNode() {
|
||||
$this->assertResult( '<div><b>Foo</b></div>' );
|
||||
}
|
||||
|
||||
function testParagraphInBlockquote() {
|
||||
$this->assertResult(
|
||||
'<blockquote>Par1
|
||||
|
||||
Par2</blockquote>',
|
||||
'<blockquote><p>Par1</p><p>Par2</p></blockquote>'
|
||||
);
|
||||
}
|
||||
|
||||
function testNoParagraphBetweenListItem() {
|
||||
$this->assertResult(
|
||||
'<ul><li>Foo</li>
|
||||
|
||||
<li>Bar</li></ul>'
|
||||
);
|
||||
}
|
||||
|
||||
function testParagraphSingleElementWithSurroundingSpace() {
|
||||
$this->assertResult(
|
||||
'<div>
|
||||
|
||||
Bar
|
||||
|
||||
</div>',
|
||||
'<div><p>Bar</p></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testIgnoreExtraSpaceWithLeadingInlineNode() {
|
||||
$this->assertResult(
|
||||
'<b>Par1</b>a
|
||||
|
||||
|
||||
|
||||
Par2',
|
||||
'<p><b>Par1</b>a</p><p>Par2</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testAbsorbExtraEndingPTag() {
|
||||
$this->assertResult(
|
||||
'Par1
|
||||
|
||||
Par2</p>',
|
||||
'<p>Par1</p><p>Par2</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testAbsorbExtraEndingDivTag() {
|
||||
$this->assertResult(
|
||||
'Par1
|
||||
|
||||
Par2</div>',
|
||||
'<p>Par1</p><p>Par2</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testDoNotParagraphSingleSurroundingSpaceInBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div>
|
||||
Par1
|
||||
</div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testBlockNodeTextDelimeterInBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div>Par1
|
||||
|
||||
<div>Par2</div></div>',
|
||||
'<div><p>Par1</p><div>Par2</div></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testBlockNodeTextDelimeterWithoutDoublespaceInBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div>Par1
|
||||
<div>Par2</div></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testBlockNodeTextDelimeterWithoutDoublespace() {
|
||||
$this->assertResult(
|
||||
'Par1
|
||||
<div>Par2</div>',
|
||||
'<p>Par1
|
||||
</p><div>Par2</div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testTwoParagraphsOfTextAndInlineNode() {
|
||||
$this->assertResult(
|
||||
'Par1
|
||||
|
||||
<b>Par2</b>',
|
||||
'<p>Par1</p><p><b>Par2</b></p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testLeadingInlineNodeParagraph() {
|
||||
$this->assertResult(
|
||||
'<img /> Foo',
|
||||
'<p><img /> Foo</p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testTrailingInlineNodeParagraph() {
|
||||
$this->assertResult(
|
||||
'<li>Foo <a>bar</a></li>'
|
||||
);
|
||||
}
|
||||
|
||||
function testTwoInlineNodeParagraph() {
|
||||
$this->assertResult(
|
||||
'<li><b>baz</b><a>bar</a></li>'
|
||||
);
|
||||
}
|
||||
|
||||
function testNoParagraphTrailingBlockNodeInBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div><div>asdf</div><b>asdf</b></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testParagraphTrailingBlockNodeWithDoublespaceInBlockNode() {
|
||||
$this->assertResult(
|
||||
'<div><div>asdf</div>
|
||||
|
||||
<b>asdf</b></div>',
|
||||
'<div><div>asdf</div><p><b>asdf</b></p></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testParagraphTwoInlineNodesAndWhitespaceNode() {
|
||||
$this->assertResult(
|
||||
'<b>One</b> <i>Two</i>',
|
||||
'<p><b>One</b> <i>Two</i></p>'
|
||||
);
|
||||
}
|
||||
|
||||
function testNoParagraphWithInlineRootNode() {
|
||||
$this->config->set('HTML', 'Parent', 'span');
|
||||
$this->assertResult(
|
||||
'Par
|
||||
|
||||
Par2'
|
||||
);
|
||||
}
|
||||
|
||||
function testInlineAndBlockTagInDivNoParagraph() {
|
||||
$this->assertResult(
|
||||
'<div><code>bar</code> mmm <pre>asdf</pre></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testInlineAndBlockTagInDivNeedingParagraph() {
|
||||
$this->assertResult(
|
||||
'<div><code>bar</code> mmm
|
||||
|
||||
<pre>asdf</pre></div>',
|
||||
'<div><p><code>bar</code> mmm</p><pre>asdf</pre></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testTextInlineNodeTextThenDoubleNewlineNeedsParagraph() {
|
||||
$this->assertResult(
|
||||
'<div>asdf <code>bar</code> mmm
|
||||
|
||||
<pre>asdf</pre></div>',
|
||||
'<div><p>asdf <code>bar</code> mmm</p><pre>asdf</pre></div>'
|
||||
);
|
||||
}
|
||||
|
||||
function testErrorNeeded() {
|
||||
$this->config->set('HTML', 'Allowed', 'b');
|
||||
$this->expectError('Cannot enable AutoParagraph injector because p is not allowed');
|
||||
$this->assertResult('<b>foobar</b>');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user