0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-12-22 08:21:52 +00:00

[3.0.0] Upgraded test scripts and other goodies. Also removed some PHP4 cruft.

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1482 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2008-01-07 00:17:49 +00:00
parent 562f53b54c
commit be7c1e7a8f
15 changed files with 273 additions and 182 deletions

2
NEWS
View File

@ -29,6 +29,8 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
Enable by setting %CSS.Proprietary to true.
- Colors missing # but in hex form will be corrected
- CSS Number algorithm improved
- Unit testing and multi-testing now on steroids: command lines,
XML output, and other goodies now added.
. Unit tests for Injector improved
. New classes:
+ HTMLPurifier_AttrDef_CSS_AlphaValue

2
TODO
View File

@ -68,8 +68,6 @@ AutoFormat
Unknown release (on a scratch-an-itch basis)
# CHMOD install script for PEAR installs
# Convert multitest to use the XML format
# Make test/index.php have better cli flags
? Have 'lang' attribute be checked against official lists, achieved by
encoding all characters that have string entity equivalents
- Abstract ChildDef_BlockQuote to work with all elements that only

View File

@ -1,7 +1,5 @@
<?php
require_once 'compat-function-file-put-contents.php';
function assertCli() {
if (php_sapi_name() != 'cli' && !getenv('PHP_IS_CLI')) {
echo 'Script cannot be called from web-browser (if you are calling via cli,

View File

@ -1,107 +0,0 @@
<?php
// $Id: file_put_contents.php,v 1.27 2007/04/17 10:09:56 arpad Exp $
if (!defined('FILE_USE_INCLUDE_PATH')) {
define('FILE_USE_INCLUDE_PATH', 1);
}
if (!defined('LOCK_EX')) {
define('LOCK_EX', 2);
}
if (!defined('FILE_APPEND')) {
define('FILE_APPEND', 8);
}
/**
* Replace file_put_contents()
*
* @category PHP
* @package PHP_Compat
* @license LGPL - http://www.gnu.org/licenses/lgpl.html
* @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
* @link http://php.net/function.file_put_contents
* @author Aidan Lister <aidan@php.net>
* @version $Revision: 1.27 $
* @internal resource_context is not supported
* @since PHP 5
* @require PHP 4.0.0 (user_error)
*/
function php_compat_file_put_contents($filename, $content, $flags = null, $resource_context = null)
{
// If $content is an array, convert it to a string
if (is_array($content)) {
$content = implode('', $content);
}
// If we don't have a string, throw an error
if (!is_scalar($content)) {
user_error('file_put_contents() The 2nd parameter should be either a string or an array',
E_USER_WARNING);
return false;
}
// Get the length of data to write
$length = strlen($content);
// Check what mode we are using
$mode = ($flags & FILE_APPEND) ?
'a' :
'wb';
// Check if we're using the include path
$use_inc_path = ($flags & FILE_USE_INCLUDE_PATH) ?
true :
false;
// Open the file for writing
if (($fh = @fopen($filename, $mode, $use_inc_path)) === false) {
user_error('file_put_contents() failed to open stream: Permission denied',
E_USER_WARNING);
return false;
}
// Attempt to get an exclusive lock
$use_lock = ($flags & LOCK_EX) ? true : false ;
if ($use_lock === true) {
if (!flock($fh, LOCK_EX)) {
return false;
}
}
// Write to the file
$bytes = 0;
if (($bytes = @fwrite($fh, $content)) === false) {
$errormsg = sprintf('file_put_contents() Failed to write %d bytes to %s',
$length,
$filename);
user_error($errormsg, E_USER_WARNING);
return false;
}
// Close the handle
@fclose($fh);
// Check all the data was written
if ($bytes != $length) {
$errormsg = sprintf('file_put_contents() Only %d of %d bytes written, possibly out of free disk space.',
$bytes,
$length);
user_error($errormsg, E_USER_WARNING);
return false;
}
// Return length
return $bytes;
}
// Define
if (!function_exists('file_put_contents')) {
function file_put_contents($filename, $content, $flags = null, $resource_context = null)
{
return php_compat_file_put_contents($filename, $content, $flags, $resource_context);
}
}

View File

@ -1,6 +1,7 @@
#!/usr/bin/php
<?php
chdir(dirname(__FILE__));
require_once 'common.php';
assertCli();

View File

@ -1,6 +1,7 @@
#!/usr/bin/php
<?php
chdir(dirname(__FILE__));
require_once 'common.php';
assertCli();

View File

@ -1,6 +1,7 @@
#!/usr/bin/php
<?php
chdir(dirname(__FILE__));
require_once 'common.php';
assertCli();

View File

@ -17,6 +17,13 @@ $simpletest_location = '/path/to/simpletest/';
// Where is CSSTidy located?
$csstidy_location = '/path/to/csstidy/';
// For tests/multitest.php, which versions to test?
$versions_to_test = array();
// For tests/multitest.php, what is the multi-version executable? It must
// accept an extra parameter (version number) before all other arguments
$phpv = 'phpv';
// How many times should profiling scripts iterate over the function? More runs
// means more accurate results, but they'll take longer to perform.
$GLOBALS['HTMLPurifierTest']['Runs'] = 2;

68
tests/CliTestCase.php Normal file
View File

@ -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()
}
}

View File

@ -35,7 +35,8 @@ class HTMLPurifier_EncoderTest extends HTMLPurifier_Harness
// UTF-8 means that we don't touch it
$this->assertIdentical(
HTMLPurifier_Encoder::convertToUTF8("\xF6", $config, $context),
"\xF6" // this is invalid
"\xF6", // this is invalid
'Expected identical [Binary: F6]'
);
$this->assertNoErrors();
@ -80,7 +81,8 @@ class HTMLPurifier_EncoderTest extends HTMLPurifier_Harness
// Now it gets converted
$this->assertIdentical(
HTMLPurifier_Encoder::convertFromUTF8("\xC3\xB6", $config, $context),
"\xF6"
"\xF6",
'Expected identical [Binary: F6]'
);
if (function_exists('iconv')) {
@ -98,7 +100,8 @@ class HTMLPurifier_EncoderTest extends HTMLPurifier_Harness
));
$this->assertIdentical(
HTMLPurifier_Encoder::convertFromUTF8("\xC3\xB6", $config, $context),
"\xF6"
"\xF6",
'Expected identical [Binary: F6]'
);
$this->assertIdentical(

View File

@ -69,7 +69,7 @@ class HTMLPurifier_EntityParserTest extends HTMLPurifier_Harness
$this->assertIdentical(
$this->EntityParser->substituteNonSpecialEntities($string),
$expect,
$arg[0] . ': %s'
'Identical expectation [Hex: '. dechex($arg[0]) .']'
);
}

View File

@ -3,27 +3,33 @@
class HTMLPurifier_SimpleTest_Reporter extends HTMLReporter
{
function paintHeader($test_name) {
protected $ac;
public function __construct($encoding, $ac) {
$this->ac = $ac;
parent::HTMLReporter($encoding);
}
public function paintHeader($test_name) {
parent::paintHeader($test_name);
$test_file = $GLOBALS['HTMLPurifierTest']['File'];
?>
<form action="" method="get" id="select">
<select name="f">
<option value="" style="font-weight:bold;"<?php if(!$test_file) {echo ' selected';} ?>>All Tests</option>
<option value="" style="font-weight:bold;"<?php if(!$this->ac['file']) {echo ' selected';} ?>>All Tests</option>
<?php foreach($GLOBALS['HTMLPurifierTest']['Files'] as $file) { ?>
<option value="<?php echo $file ?>"<?php
if ($test_file == $file) echo ' selected';
if ($this->ac['file'] == $file) echo ' selected';
?>><?php echo $file ?></option>
<?php } ?>
</select>
<input type="checkbox" name="standalone" title="Standalone version?" <?php if(isset($_GET['standalone'])) {echo 'checked="checked" ';} ?>/>
<input type="checkbox" name="standalone" title="Standalone version?" <?php if($this->ac['standalone']) {echo 'checked="checked" ';} ?>/>
<input type="submit" value="Go">
</form>
<?php
flush();
}
function _getCss() {
public function _getCss() {
$css = parent::_getCss();
$css .= '
#select {position:absolute;top:0.2em;right:0.2em;}

View File

@ -1,6 +1,9 @@
<?php
if (!defined('HTMLPurifierTest')) exit;
if (!defined('HTMLPurifierTest')) {
echo "Invalid entry point\n";
exit;
}
// default settings (protect against register_globals)
$GLOBALS['HTMLPurifierTest'] = array();
@ -10,6 +13,8 @@ $GLOBALS['HTMLPurifierTest']['PH5P'] = class_exists('DOMDocument');
// default library settings
$simpletest_location = 'simpletest/'; // reasonable guess
$csstidy_location = false;
$versions_to_test = array();
$phpv = 'phpv';
// load configuration
if (file_exists('../conf/test-settings.php')) include '../conf/test-settings.php';
@ -19,6 +24,7 @@ if (file_exists('../test-settings.php')) include '../test-settings.php';
require_once $simpletest_location . 'unit_tester.php';
require_once $simpletest_location . 'reporter.php';
require_once $simpletest_location . 'mock_objects.php';
require_once $simpletest_location . 'xml.php';
// load CSS Tidy
if ($csstidy_location !== false) {
@ -38,8 +44,62 @@ error_reporting(E_ALL | E_STRICT);
// load SimpleTest addons
require_once 'HTMLPurifier/SimpleTest/Reporter.php';
require_once 'CliTestCase.php';
require_once 'Debugger.php';
require_once 'generate_mock_once.func.php';
require_once 'path2class.func.php';
require_once 'tally_errors.func.php'; // compat
/**
* Arguments parser, is cli and web agnostic.
* @warning
* There are some quirks about the argument format:
* - Short flags cannot be chained together
* - Any number of hyphens are allowed to lead flags
* - Flag values cannot have spaces in them
* - You must specify an equal sign, --foo=value; --foo value doesn't work
* - Only strings and booleans are accepted
* - This --flag=off will be interpreted as true, use --flag=0 instead
* @param $AC
* Arguments array to populate. This takes a simple format of 'argument'
* => default value. Depending on the type of the default value,
* arguments will be typecast accordingly. For example, if
* 'flag' => false is passed, all arguments for that will be cast to
* boolean. Do *not* pass null, as it will not be recognized.
* @param $aliases
*
*/
function htmlpurifier_parse_args(&$AC, $aliases) {
if (empty($_GET)) {
array_shift($_SERVER['argv']);
foreach ($_SERVER['argv'] as $opt) {
if (strpos($opt, "=") !== false) {
list($o, $v) = explode("=", $opt, 2);
} else {
$o = $opt;
$v = true;
}
$o = ltrim($o, '-');
htmlpurifier_args($AC, $aliases, $o, $v);
}
} else {
foreach ($_GET as $o => $v) {
if (get_magic_quotes_gpc()) $v = stripslashes($v);
htmlpurifier_args($AC, $aliases, $o, $v);
}
}
}
/**
* Actually performs assignment to $AC, see htmlpurifier_parse_args()
* @param $AC Arguments array to write to
* @param $aliases Aliases for options
* @param $o Argument name
* @param $v Argument value
*/
function htmlpurifier_args(&$AC, $aliases, $o, $v) {
if (isset($aliases[$o])) $o = $aliases[$o];
if (!isset($AC[$o])) return;
if (is_string($AC[$o])) $AC[$o] = $v;
if (is_bool($AC[$o])) $AC[$o] = true;
}

View File

@ -1,19 +1,38 @@
<?php
// call one file using /?f=FileTest.php , see $test_files array for
// valid values
/** @file
* Unit tester
*
* The heart and soul of HTML Purifier's correctness; anything and everything
* is tested here! Arguments are specified like --arg=opt, allowed arguments
* are:
* - flush, whether or not to flush definition caches before running
* - standalone, whether or not to test the standalone version
* - file (f), a single file to test
* - xml, whether or not to output XML
*/
define('HTMLPurifierTest', 1);
define('HTMLPURIFIER_SCHEMA_STRICT', true); // validate schemas
require_once 'common.php';
$AC = array(); // parameters
$AC['flush'] = false;
$AC['standalone'] = false;
$AC['file'] = '';
$AC['xml'] = false;
$aliases = array(
'f' => 'file',
);
htmlpurifier_parse_args($AC, $aliases);
// clean out cache if necessary
if (isset($_GET['flush'])) shell_exec('php ../maintenance/flush-definition-cache.php');
if ($AC['flush']) shell_exec('php ../maintenance/flush-definition-cache.php');
// initialize and load HTML Purifier
// use ?standalone to load the alterative standalone stub
if (isset($_GET['standalone']) || (isset($argv[1]) && $argv[1] == 'standalone')) {
if ($AC['standalone']) {
set_include_path(realpath('blanks') . PATH_SEPARATOR . get_include_path());
require_once '../library/HTMLPurifier.standalone.php';
} else {
@ -33,25 +52,25 @@ $GLOBALS['HTMLPurifierTest']['Files'] = $test_files; // for the reporter
$test_file_lookup = array_flip($test_files);
// determine test file
if (isset($_GET['f']) && isset($test_file_lookup[$_GET['f']])) {
$GLOBALS['HTMLPurifierTest']['File'] = $_GET['f'];
} elseif (isset($argv[1]) && isset($test_file_lookup[$argv[1]])) {
// command-line
$GLOBALS['HTMLPurifierTest']['File'] = $argv[1];
} else {
$GLOBALS['HTMLPurifierTest']['File'] = false;
if ($AC['file']) {
if (!isset($test_file_lookup[$AC['file']])) {
echo "Invalid file passed\n";
exit;
}
}
// we can't use addTestFile because SimpleTest chokes on E_STRICT warnings
if ($test_file = $GLOBALS['HTMLPurifierTest']['File']) {
if ($AC['file']) {
$test = new GroupTest($test_file);
require_once $test_file;
$test->addTestClass(path2class($test_file));
$test = new TestSuite($AC['file']);
require_once $AC['file'];
$test->addTestClass(path2class($AC['file']));
} else {
$test = new GroupTest('All HTML Purifier tests on PHP ' . PHP_VERSION);
$standalone = '';
if ($AC['standalone']) $standalone = ' (standalone)';
$test = new TestSuite('All HTML Purifier tests on PHP ' . PHP_VERSION . $standalone);
foreach ($test_files as $test_file) {
require_once $test_file;
$test->addTestClass(path2class($test_file));
@ -59,7 +78,13 @@ if ($test_file = $GLOBALS['HTMLPurifierTest']['File']) {
}
if (SimpleReporter::inCli()) $reporter = new TextReporter();
else $reporter = new HTMLPurifier_SimpleTest_Reporter('UTF-8');
if ($AC['xml']) {
if (!SimpleReporter::inCli()) header('Content-Type: text/xml;charset=UTF-8');
$reporter = new XmlReporter();
} elseif (SimpleReporter::inCli()) {
$reporter = new TextReporter();
} else {
$reporter = new HTMLPurifier_SimpleTest_Reporter('UTF-8', $AC);
}
$test->run($reporter);

View File

@ -3,49 +3,77 @@
/** @file
* Multiple PHP Versions test
*
* This file tests HTML Purifier in all versions of PHP. It requires a
* script called phpv that takes an extra argument, $version, before
* the filename, is required. Contact me if you'd like to set up a
* similar script.
* This file tests HTML Purifier in all versions of PHP. Arguments
* are specified like --arg=opt, allowed arguments are:
* - exclude-normal, excludes normal tests
* - exclude-standalone, excludes standalone tests
* - file (f), specifies a single file to test for all versions
* - xml, if specified output is XML
* - quiet (q), if specified no informative messages are enabled (please use
* this if you're outputting XML)
*
* @note
* It requires a script called phpv that takes an extra argument (the
* version number of PHP) before all other arguments. Contact me if you'd
* like to set up a similar script. The name of the script can be
* edited with $phpv
*
* @note
* Also, configuration must be set up with a variable called
* $versions_to_test specifying version numbers to pass to $phpv
*/
$versions_to_test = array(
'FLUSH',
'5.0.0',
'5.0.1',
'5.0.2',
'5.0.3',
'5.0.4',
'5.0.5',
'5.1.0',
'5.1.1',
'5.1.2',
'5.1.3',
'5.1.4',
// '5.1.5', // zip appears to be missing
'5.1.6',
'5.2.0',
'5.2.1',
'5.2.2',
'5.2.3',
'5.2.4',
'5.2.5',
'5.3.0-dev',
// '6.0.0-dev',
);
define('HTMLPurifierTest', 1);
require_once 'common.php';
echo str_repeat('-', 70) . "\n";
echo "HTML Purifier\n";
echo "Multiple PHP Versions Test\n\n";
passthru("php ../maintenance/merge-library.php");
foreach ($versions_to_test as $version) {
if ($version === 'FLUSH') {
shell_exec('php ../maintenance/flush-definition-cache.php');
continue;
}
passthru("phpv $version index.php");
passthru("phpv $version index.php standalone");
echo "\n\n";
if (!SimpleReporter::inCli()) {
echo 'Multitest only available from command line';
exit;
}
$AC = array(); // parameters
$AC['exclude-normal'] = false;
$AC['exclude-standalone'] = false;
$AC['file'] = '';
$AC['xml'] = false;
$AC['quiet'] = false;
$aliases = array(
'f' => 'file',
'q' => 'quiet',
);
htmlpurifier_parse_args($AC, $aliases);
shell_exec("php ../maintenance/merge-library.php");
shell_exec('php ../maintenance/flush-definition-cache.php');
$test = new TestSuite('HTML Purifier Multiple Versions Test');
$file = '';
if ($AC['file']) {
$test_files = array();
require 'test_files.php';
$test_files_lookup = array_flip($test_files);
if (isset($test_files_lookup[$AC['file']])) {
$file = '--file=' . $AC['file'];
} else {
echo "Invalid file passed\n";
exit;
}
}
foreach ($versions_to_test as $version) {
$flush = '';
if (is_array($version)) {
$version = $version[0];
$flush = '--flush';
}
if (!$AC['exclude-normal']) $test->addTestCase(new CliTestCase("$phpv $version index.php --xml $flush $file", $AC['quiet']));
if (!$AC['exclude-standalone']) $test->addTestCase(new CliTestCase("$phpv $version index.php --xml --standalone $file", $AC['quiet']));
}
if ($AC['xml']) {
$reporter = new XmlReporter();
} else {
$reporter = new TextReporter();
}
$test->run($reporter);
shell_exec('php ../maintenance/flush-definition-cache.php');