3 +----------------------------------------------------------------------+
5 +----------------------------------------------------------------------+
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
16 | Authors: Ilia Alshanetsky <ilia@php.net> |
17 | Preston L. Bannister <pbannister@php.net> |
18 | Marcus Boerger <helly@php.net> |
19 | Shane Caraveo <shane@php.net> |
20 | Derick Rethans <derick@php.net> |
21 | Sander Roobol <sander@php.net> |
22 | (based on version by: Stig Bakken <ssb@php.net>) |
23 | (based on the PHP 3 test framework by Rasmus Lerdorf) |
24 +----------------------------------------------------------------------+
28 while(@ob_end_clean
());
29 if (ob_get_level()) echo "Not all buffers were deleted.\n";
30 error_reporting(E_ALL
);
32 /**********************************************************************
36 define('PHP_QA_EMAIL', 'qa-reports@lists.php.net');
37 define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php');
39 /**********************************************************************
43 define('PCRE_MISSING_ERROR',
44 '+-----------------------------------------------------------+
46 | The test-suite requires that you have pcre extension |
47 | enabled. To enable this extension either compile your PHP |
48 | with --with-pcre-regex or if you have compiled pcre as a |
49 | shared module load it via php.ini. |
50 +-----------------------------------------------------------+');
51 define('SAFE_MODE_WARNING',
52 '+-----------------------------------------------------------+
54 | You are running the test-suite with "safe_mode" ENABLED ! |
56 | Chances are high that no test will work at all, |
57 | depending on how you configured "safe_mode" ! |
58 +-----------------------------------------------------------+');
60 '+-----------------------------------------------------------+
62 | You must create /tmp for session tests to work! |
64 +-----------------------------------------------------------+');
65 define('PROC_OPEN_MISSING',
66 '+-----------------------------------------------------------+
68 | The test-suite requires that proc_open() is available. |
69 | Please check if you disabled it in php.ini. |
70 +-----------------------------------------------------------+');
71 define('REQ_PHP_VERSION',
72 '+-----------------------------------------------------------+
74 | The test-suite must be run with PHP 5 or later. |
75 | You can still test older extecutables by setting |
76 | TEST_PHP_EXECUTABLE and running this script with PHP 5. |
77 +-----------------------------------------------------------+');
78 /**********************************************************************
81 define('PHP_INFO_SCRIPT','<?php echo "
82 PHP_SAPI=" . PHP_SAPI . "
83 PHP_VERSION=" . phpversion() . "
84 ZEND_VERSION=" . zend_version() . "
86 INCLUDE_PATH=" . get_cfg_var("include_path") . "
87 INI=" . realpath(get_cfg_var("cfg_file_path")) . "
88 SCANNED_INI=" . (function_exists(\'php_ini_scanned_files\') ?
89 str_replace("\n","", php_ini_scanned_files()) :
90 "** not determined **") . "
91 SERVER_SOFTWARE=" . (isset($_ENV[\'SERVER_SOFTWARE\']) ? $_ENV[\'SERVER_SOFTWARE\'] : \'UNKNOWN\');
94 define('PHP_EXTENSIONS_SCRIPT','<?php print join(get_loaded_extensions(),":"); ?>');
95 define('PHP_INI_SETTINGS_SCRIPT','<?php echo serialize(ini_get_all()); ?>');
97 /**********************************************************************
98 * various utility functions
101 function settings2array($settings, &$ini_settings)
103 foreach($settings as $setting) {
104 if (strpos($setting, '=')!==false) {
105 $setting = explode("=", $setting, 2);
106 $name = trim($setting[0]);
107 $value = trim($setting[1]);
108 $ini_settings[$name] = $value;
113 function settings2params(&$ini_settings)
116 if (count($ini_settings)) {
117 foreach($ini_settings as $name => $value) {
118 $value = addslashes($value);
119 $settings .= " -d \"".strtolower($name)."=$value\"";
125 function generate_diff($wanted,$output)
127 $w = explode("\n", $wanted);
128 $o = explode("\n", $output);
129 $w1 = array_diff_assoc($w,$o);
130 $o1 = array_diff_assoc($o,$w);
133 foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+
1).$val;
134 foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+
1).$val;
135 $diff = array_merge($w2, $o2);
137 return implode("\r\n", $diff);
140 function mkpath($path,$mode = 0777) {
141 $dirs = split('[\\/]',$path);
143 for($i = 1;$i < count($dirs);$i++
) {
144 $path .= '/'.$dirs[$i];
149 function copyfiles($src,$new) {
151 while (($entry = $d->read())) {
152 if (is_file("$src/$entry")) {
153 copy("$src/$entry", "$new/$entry");
159 function post_result_data($query,$data)
161 $url = QA_SUBMISSION_PAGE
.'?'.$query;
162 $post = "php_test_data=" . urlencode(base64_encode(preg_replace("/[\\x00]/", "[0x0]", $data)));
163 $r = new HTTPRequest($url,NULL,NULL,$post);
164 return $this->response_headers
['Status']=='200';
168 function execute($command, $args=NULL, $input=NULL, $cwd=NULL, $env=NULL)
172 if (gettype($args)=='array') {
173 $args = join($args,' ');
175 $commandline = "$command $args";
176 $proc = proc_open($commandline, array(
177 0 => array('pipe', 'r'),
178 1 => array('pipe', 'w')),
185 $out = fwrite($pipes[0],$input);
186 if ($out != strlen($input)) {
194 /* hide errors from interrupted syscalls */
198 $n = @stream_select
($r, $w, $e, 60);
202 $data .= "\n ** ERROR: process timed out **\n";
203 proc_terminate($proc);
206 $line = fread($pipes[1], 8192);
207 if (strlen($line) == 0) {
214 $code = proc_close($proc);
218 function executeCode($php, $ini_overwrites, $code, $remove_headers=true, $cwd=NULL, $env=NULL)
221 if ($ini_overwrites) {
222 $info_params = array();
223 settings2array($ini_overwrites,$info_params);
224 $params = settings2params($info_params);
226 $out = execute($php, $params, $code, $cwd, $env);
228 if ($remove_headers && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
235 /**********************************************************************
236 * a simple request class that lets us handle http based tests
241 public $headers = array();
243 public $urlparts = NULL;
245 public $userAgent = 'PHP-Test-Harness';
246 public $options = array();
247 public $postdata = NULL;
251 public $response_headers;
252 public $outgoing_payload;
253 public $incoming_payload = '';
257 headers is assoc array of outgoing http headers
267 post data is, well, post data. It is not processed so
268 multipart stuff must be prepared before calling this
271 function HTTPRequest($URL, $headers=array(), $options=array(), $postdata=NULL)
273 $this->urlparts
= @parse_url
($URL);
275 $this->options
= $options;
276 $this->headers
= $headers;
277 $this->postdata
= &$postdata;
283 if (!$this->_validateUrl()) return;
285 if (isset($this->options
['timeout']))
286 $this->timeout
= (int)$this->options
['timeout'];
291 function _validateUrl()
293 if ( ! is_array($this->urlparts
) ) {
296 if (!isset($this->urlparts
['host'])) {
297 $this->urlparts
['host']='127.0.0.1';
299 if (!isset($this->urlparts
['port'])) {
300 $this->urlparts
['port'] = 80;
302 if (!isset($this->urlparts
['path']) ||
!$this->urlparts
['path'])
303 $this->urlparts
['path'] = '/';
307 function _parseResponse()
309 if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $this->incoming_payload
, $match)) {
310 $this->response
= $match[2];
311 if (preg_match("/^HTTP\/1\.. (\d+).*/s",$match[1],$status) && !$status[1]) {
312 $this->errmsg
= "HTTP Response $status[1] Not Found";
315 $rh = preg_split("/[\n\r]+/",$match[1]);
316 $this->response_headers
= array();
317 foreach ($rh as $line) {
318 if (strpos($line, ':')!==false) {
319 $line = explode(":", $line, 2);
320 $this->response_headers
[trim($line[0])] = trim($line[1]);
323 $this->response_headers
['Status']=$status[1];
324 // if no content, return false
325 if(strlen($this->response
) > 0) return TRUE;
327 $this->errmsg
= 'Invalid HTTP Response';
331 function &_getRequest()
333 $fullpath = $this->urlparts
['path'].
334 (isset($this->urlparts
['query'])?
'?'.$this->urlparts
['query']:'').
335 (isset($this->urlparts
['fragment'])?
'#'.$this->urlparts
['fragment']:'');
336 if (isset($this->options
['proxy_host'])) {
337 $fullpath = 'http://'.$this->urlparts
['host'].':'.$this->urlparts
['port'].$fullpath;
339 if (isset($this->options
['proxy_user'])) {
340 $headers['Proxy-Authorization'] = 'Basic ' . base64_encode($this->options
['proxy_user'].":".$this->options
['proxy_pass']);
342 $headers['User-Agent'] = $this->userAgent
;
343 $headers['Host'] = $this->urlparts
['host'];
344 $headers['Content-Length'] = strlen($this->postdata
);
345 $headers['Content-Type'] = 'application/x-www-form-urlencoded';
346 if (isset($this->headers
)) {
347 $headers = array_merge($headers, $this->headers
);
350 foreach ($headers as $k => $v) {
351 $headertext .= "$k: $v\r\n";
353 $method = trim($this->options
['method'])?
strtoupper(trim($this->options
['method'])):'GET';
354 $this->outgoing_payload
=
355 "$method $fullpath HTTP/1.0\r\n".
358 return $this->outgoing_payload
;
361 function &_sendHTTP()
363 $this->_getRequest();
364 $host = $this->urlparts
['host'];
365 $port = $this->urlparts
['port'];
366 if (isset($this->options
['proxy_host'])) {
367 $host = $this->options
['proxy_host'];
368 $port = isset($this->options
['proxy_port'])?
$this->options
['proxy_port']:8080;
371 if ($this->timeout
> 0) {
372 $fp = fsockopen($host, $port, $this->errno
, $this->errmsg
, $this->timeout
);
374 $fp = fsockopen($host, $port, $this->errno
, $this->errmsg
);
377 $this->errmsg
= "Connect Error to $host:$port";
380 if ($this->timeout
> 0) {
381 // some builds of php do not support this, silence
383 @socket_set_timeout
($fp, $this->timeout
);
385 if (!fputs($fp, $this->outgoing_payload
, strlen($this->outgoing_payload
))) {
386 $this->errmsg
= "Error Sending Request Data to $host";
390 while ($data = fread($fp, 32768)) {
391 $this->incoming_payload
.= $data;
396 $this->_parseResponse();
400 #$r = new HTTPRequest('http://localhost:81/info.php/path/info');
401 #print_r($r->response_headers);
407 /**********************************************************************
413 public $xargs = array(
414 #arg env var value default description
415 'c' => array('' ,'file' ,NULL ,'configuration file, see server-tests-config.php for example'),
416 'd' => array('TEST_PATHS' ,'paths' ,NULL ,'colon seperate path list'),
417 'e' => array('TEST_PHP_ERROR_STYLE','EMACS|MSVC' ,'EMACS' ,'editor error style'),
418 'h' => array('' ,'' ,NULL ,'this help'),
419 'i' => array('PHPRC' ,'path|file' ,NULL ,'ini file to use for tests (sets PHPRC)'),
420 'l' => array('TEST_PHP_LOG_FORMAT' ,'string' ,'LEODC' ,'any combination of CDELO'),
421 'm' => array('TEST_BASE_PATH' ,'path' ,NULL ,'copy tests to this path before testing'),
422 'n' => array('NO_PHPTEST_SUMMARY' ,'' ,0 ,'do not print test summary'),
423 'p' => array('TEST_PHP_EXECUTABLE' ,'path' ,NULL ,'php executable to be tested'),
424 'q' => array('NO_INTERACTION' ,'' ,0 ,'no console interaction (ie dont contact QA)'),
425 'r' => array('REPORT_EXIT_STATUS' ,'' ,0 ,'exit with status at end of execution'),
426 's' => array('TEST_PHP_SRCDIR' ,'path' ,NULL ,'path to php source code'),
427 't' => array('TEST_PHP_DETAILED' ,'number' ,0 ,'level of detail output to dump'),
428 'u' => array('TEST_WEB_BASE_URL' ,'url' ,'' ,'base url for http testing'),
429 'v' => array('TEST_CONTEXT_INFO' ,'' ,0 ,'view text executable context info'),
430 'w' => array('TEST_WEB' ,'' ,0 ,'run tests via http'),
431 'x' => array('TEST_WEB_EXT' ,'file ext' ,'php' ,'http file extension to use')
434 public $conf = array();
435 public $test_to_run = array();
436 public $test_files = array();
437 public $test_results = array();
438 public $failed_tests = array();
439 public $exts_to_test;
440 public $exts_tested = 0;
441 public $exts_skipped = 0;
442 public $ignored_by_ext = 0;
443 public $test_dirs = array('tests', 'pear', 'ext', 'sapi');
447 public $test_executable_iscgi = false;
448 public $inisettings; // the test executables settings, used for web tests
449 public $iswin32 = false;
451 public $ddash = "=====================================================================";
452 public $sdash = "---------------------------------------------------------------------";
454 // Default ini settings
455 public $ini_overwrites = array(
456 'output_handler'=>'',
457 'zlib.output_compression'=>'Off',
460 'disable_functions'=>'',
461 'output_buffering'=>'Off',
462 'error_reporting'=>'4095',
463 'display_errors'=>'1',
467 'report_memleaks'=>'1',
468 'report_zend_debug'=>'0',
469 'docref_root'=>'/phpmanual/',
470 'docref_ext'=>'.html',
471 'error_prepend_string'=>'',
472 'error_append_string'=>'',
473 'auto_prepend_file'=>'',
474 'auto_append_file'=>'',
475 'magic_quotes_runtime'=>'0',
477 public $env = array();
478 public $info_params = array();
480 function testHarness() {
481 $this->iswin32
= substr(PHP_OS
, 0, 3) == "WIN";
482 $this->checkRequirements();
484 $this->removeSensitiveEnvVars();
486 $this->initializeConfiguration();
488 $this->setTestPaths();
489 # change to working directory
490 if ($this->conf
['TEST_PHP_SRCDIR']) {
491 @chdir
($this->conf
['TEST_PHP_SRCDIR']);
493 $this->cwd
= getcwd();
495 if (!$this->conf
['TEST_PHP_SRCDIR'])
496 $this->conf
['TEST_PHP_SRCDIR'] = $this->cwd
;
497 if (!$this->conf
['TEST_BASE_PATH'] && $this->conf
['TEST_PHP_SRCDIR'])
498 $this->conf
['TEST_BASE_PATH'] = $this->conf
['TEST_PHP_SRCDIR'];
499 if ($this->iswin32
) {
500 $this->conf
['TEST_PHP_SRCDIR'] = str_replace('/','\\',$this->conf
['TEST_PHP_SRCDIR']);
501 $this->conf
['TEST_BASE_PATH'] = str_replace('/','\\',$this->conf
['TEST_BASE_PATH']);
504 if (!$this->conf
['TEST_WEB'] && !is_executable($this->conf
['TEST_PHP_EXECUTABLE'])) {
505 $this->error("invalid PHP executable specified by TEST_PHP_EXECUTABLE = " .
506 $this->conf
['TEST_PHP_EXECUTABLE']);
510 $this->getInstalledExtensions();
511 $this->getExecutableInfo();
512 $this->getExecutableIniSettings();
513 $this->test_executable_iscgi
= strncmp($this->exec_info
['PHP_SAPI'],'cgi',3)==0;
514 $this->calculateDocumentRoot();
516 // add TEST_PHP_SRCDIR to the include path, this facilitates
517 // tests including files from src/tests
518 //$this->ini_overwrites['include_path'] = $this->cwd.($this->iswin32?';.;':':.:').$this->exec_info['INCLUDE_PATH'];
521 settings2array($this->ini_overwrites
,$params);
522 $this->info_params
= settings2params($params);
524 $this->contextHeader();
525 if ($this->conf
['TEST_CONTEXT_INFO']) return;
526 $this->loadFileList();
527 $this->moveTestFiles();
529 $this->summarizeResults();
532 function getExecutableIniSettings()
534 $out = $this->runscript(PHP_INI_SETTINGS_SCRIPT
,true);
535 $this->inisettings
= unserialize($out);
538 function getExecutableInfo()
540 $out = $this->runscript(PHP_INFO_SCRIPT
,true);
541 $out = preg_split("/[\n\r]+/",$out);
543 foreach ($out as $line) {
544 if (strpos($line, '=')!==false) {
545 $line = explode("=", $line, 2);
546 $name = trim($line[0]);
547 $value = trim($line[1]);
548 $info[$name] = $value;
551 $this->exec_info
= $info;
554 function getInstalledExtensions()
556 // get the list of installed extensions
557 $out = $this->runscript(PHP_EXTENSIONS_SCRIPT
,true);
558 $this->exts_to_test
= split(":",$out);
559 sort($this->exts_to_test
);
560 $this->exts_tested
= count($this->exts_to_test
);
563 // if running local, calls executeCode,
564 // otherwise does an http request
565 function runscript($script,$removeheaders=false,$cwd=NULL)
567 if ($this->conf
['TEST_WEB']) {
568 $pi = '/testscript.' . $this->conf
['TEST_WEB_EXT'];
569 if (!$cwd) $cwd = $this->conf
['TEST_BASE_PATH'];
570 $tmp_file = "$cwd$pi";
571 $pi = substr($cwd,strlen($this->conf
['TEST_BASE_PATH'])) . $pi;
572 $url = $this->conf
['TEST_WEB_BASE_URL'] . $pi;
573 file_put_contents($tmp_file,$script);
574 $fd = fopen($url, "rb");
578 $out .= fread($fd, 8192);
582 if (0 && $removeheaders &&
583 preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
588 return executeCode($this->conf
['TEST_PHP_EXECUTABLE'],$this->ini_overwrites
, $script,$removeheaders,$cwd,$this->env
);
593 // Use this function to do any displaying of text, so that
594 // things can be over-written as necessary.
596 function writemsg($msg) {
602 // Another wrapper function, this one should be used any time
603 // a particular test passes or fails
605 function showstatus($item, $status, $reason = '') {
609 $this->writemsg("PASSED: $item ($reason)\n");
612 $this->writemsg("FAILED: $item ($reason)\n");
615 $this->writemsg("SKIPPED: $item ($reason)\n");
623 $usage = "usage: php run-tests.php [options]\n";
624 foreach ($this->xargs
as $arg=>$arg_info) {
625 $usage .= sprintf(" -%s %-12s %s\n",$arg,$arg_info[1],$arg_info[3]);
630 function parseArgs() {
636 $argv = $_SERVER['argv'];
637 $argc = $_SERVER['argc'];
641 for ($i=1; $i<$argc;) {
642 if ($argv[$i][0] != '-') continue;
643 $opt = $argv[$i++
][1];
644 if (isset($value)) unset($value);
645 if (@$argv[$i][0] != '-') {
646 @$value = $argv[$i++
];
650 /* TODO: Implement configuraiton file */
653 $this->writemsg("Invalid configuration file\n");
656 $this->conf
= array_merge($this->conf
,$conf);
659 $this->conf
['TEST_PHP_ERROR_STYLE'] = strtoupper($value);
665 if ($this->xargs
[$opt][1] && isset($value))
666 $this->conf
[$this->xargs
[$opt][0]] = $value;
667 else if (!$this->xargs
[$opt][1])
668 $this->conf
[$this->xargs
[$opt][0]] = isset($value)?
$value:1;
670 $this->error("Invalid argument setting for argument $opt, should be [{$this->xargs[$opt][1]}]\n");
675 // set config into environment, this allows
676 // executed tests to find out about the test
677 // configurations. config file or args overwrite
678 // env var config settings
679 $this->env
= array_merge($this->env
,$this->conf
);
680 if (!$this->conf
['TEST_WEB'] && !$this->conf
['TEST_PHP_EXECUTABLE']) {
681 $this->writemsg($this->help());
686 function removeSensitiveEnvVars()
688 # delete sensitive env vars
689 $this->env
['SSH_CLIENT']='deleted';
690 $this->env
['SSH_AUTH_SOCK']='deleted';
691 $this->env
['SSH_TTY']='deleted';
694 function setEnvConfigVar($name)
696 if (isset($this->env
[$name])) {
697 $this->conf
[$name] = $this->env
[$name];
701 function initializeConfiguration()
703 foreach ($this->xargs
as $arg=>$arg_info) {
705 # initialize the default setting
706 $this->conf
[$arg_info[0]]=$arg_info[2];
707 # get config from environment
708 $this->setEnvConfigVar($arg_info[0]);
713 function setTestPaths()
715 // configure test paths from config file or command line
716 if (@$this->conf
['TEST_PATHS']) {
717 $this->test_dirs
= array();
718 if ($this->iswin32
) {
719 $paths = split(';',$this->conf
['TEST_PATHS']);
721 $paths = split(':|;',$this->conf
['TEST_PATHS']);
723 foreach($paths as $path) {
724 $this->test_dirs
[] = realpath($path);
729 function test_sort($a, $b) {
730 $ta = strpos($a, "{$this->cwd}/tests")===0 ?
1 +
(strpos($a, "{$this->cwd}/tests/run-test")===0 ?
1 : 0) : 0;
731 $tb = strpos($b, "{$this->cwd}/tests")===0 ?
1 +
(strpos($b, "{$this->cwd}/tests/run-test")===0 ?
1 : 0) : 0;
733 return strcmp($a, $b);
739 function checkRequirements() {
740 if (version_compare(phpversion(), "5.0") < 0) {
741 $this->writemsg(REQ_PHP_VERSION
);
744 // We might want to check another server so we won't see that server's /tmp
745 // if (!file_exists("/tmp")) {
746 // $this->writemsg(TMP_MISSING);
749 if (!function_exists("proc_open")) {
750 $this->writemsg(PROC_OPEN_MISSING
);
753 if (!extension_loaded("pcre")) {
754 $this->writemsg(PCRE_MISSING_ERROR
);
757 if (ini_get('safe_mode')) {
758 $this->writemsg(SAFE_MODE_WARNING
);
763 // Write test context information.
765 function contextHeader()
768 foreach ($this->exec_info
as $k=>$v) {
769 $info .= sprintf("%-20.s: %s\n",$k,$v);
772 foreach ($this->exts_to_test
as $ext) {
776 foreach ($this->test_dirs
as $test_dir) {
777 $dirs .= "$test_dir\n ";
780 foreach ($this->conf
as $k=>$v) {
781 $conf .= sprintf("%-20.s: %s\n",$k,$v);
785 if (!$this->conf
['TEST_WEB'])
786 $exeinfo = "CWD : {$this->cwd}\n".
787 "PHP : {$this->conf['TEST_PHP_EXECUTABLE']}\n";
789 $this->writemsg("\n$this->ddash\n".
791 "Test Harness Configuration:\n$conf\n".
792 "Extensions : $exts\n".
793 "Test Dirs : $dirs\n".
797 function loadFileList()
799 foreach ($this->test_dirs
as $dir) {
801 $this->findFilesInDir($dir, ($dir == 'ext'));
803 $this->test_files
[] = $dir;
806 usort($this->test_files
,array($this,"test_sort"));
807 $this->writemsg("found ".count($this->test_files
)." files\n");
810 function moveTestFiles()
812 if (!$this->conf
['TEST_BASE_PATH'] ||
813 $this->conf
['TEST_BASE_PATH'] == $this->conf
['TEST_PHP_SRCDIR']) return;
814 $this->writemsg("moving files from {$this->conf['TEST_PHP_SRCDIR']} to {$this->conf['TEST_BASE_PATH']}\n");
815 $l = strlen($this->conf
['TEST_PHP_SRCDIR']);
818 foreach ($this->test_files
as $file) {
819 if (strpos($file,$this->conf
['TEST_PHP_SRCDIR'])==0) {
820 $newlocation = $this->conf
['TEST_BASE_PATH'].substr($file,$l);
821 $files[] = $newlocation;
822 $dirs[dirname($file)] = dirname($newlocation);
824 // XXX what to do with test files outside the
825 // php source directory? Need to map them into
826 // the new directory somehow.
829 foreach ($dirs as $src=>$new) {
831 copyfiles($src,$new);
833 $this->test_files
= $files;
836 function findFilesInDir($dir,$is_ext_dir=FALSE,$ignore=FALSE)
838 $skip = array('.', '..', 'CVS');
839 $o = opendir($dir) or $this->error("cannot open directory: $dir");
840 while (($name = readdir($o)) !== FALSE) {
841 if (in_array($name, $skip)) continue;
842 if (is_dir("$dir/$name")) {
843 $skip_ext = ($is_ext_dir && !in_array($name, $this->exts_to_test
));
845 $this->exts_skipped++
;
847 $this->findFilesInDir("$dir/$name", FALSE, $ignore ||
$skip_ext);
850 // Cleanup any left-over tmp files from last run.
851 if (substr($name, -4) == '.tmp') {
852 @unlink
("$dir/$name");
856 // Otherwise we're only interested in *.phpt files.
857 if (substr($name, -5) == '.phpt') {
859 $this->ignored_by_ext++
;
861 $testfile = realpath("$dir/$name");
862 $this->test_files
[] = $testfile;
871 $this->writemsg("TIME START " . date('Y-m-d H:i:s', $this->start_time
) . "\n".$this->ddash
."\n");
872 if (count($this->test_to_run
)) {
873 $this->writemsg("Running selected tests.\n");
875 $this->writemsg("Running all test files.\n");
881 $this->start_time
= time();
883 // Run selected tests.
884 if (count($this->test_to_run
)) {
886 foreach($this->test_to_run
as $name=>$runnable) {
887 if(!preg_match("/\.phpt$/", $name))
890 $this->test_results
[$name] = $this->run_test($name);
894 foreach ($this->test_files
as $name) {
895 $this->test_results
[$name] = $this->run_test($name);
898 $this->end_time
= time();
901 function summarizeResults()
903 if (count($this->test_results
) == 0) {
904 $this->writemsg("No tests were run.\n");
908 $n_total = count($this->test_results
);
909 $n_total +
= $this->ignored_by_ext
;
911 $sum_results = array('PASSED'=>0, 'SKIPPED'=>0, 'FAILED'=>0);
912 foreach ($this->test_results
as $v) {
915 $sum_results['SKIPPED'] +
= $this->ignored_by_ext
;
916 $percent_results = array();
917 while (list($v,$n) = each($sum_results)) {
918 $percent_results[$v] = (100.0 * $n) / $n_total;
921 $this->writemsg("\n".$this->ddash
."\n".
922 "TIME END " . date('Y-m-d H:i:s', $this->end_time
) . "\n".
924 "TEST RESULT SUMMARY\n".
926 "Exts skipped : " . sprintf("%4d",$this->exts_skipped
) . "\n".
927 "Exts tested : " . sprintf("%4d",$this->exts_tested
) . "\n".
929 "Number of tests : " . sprintf("%4d",$n_total) . "\n".
930 "Tests skipped : " . sprintf("%4d (%2.1f%%)",$sum_results['SKIPPED'],$percent_results['SKIPPED']) . "\n".
931 "Tests failed : " . sprintf("%4d (%2.1f%%)",$sum_results['FAILED'],$percent_results['FAILED']) . "\n".
932 "Tests passed : " . sprintf("%4d (%2.1f%%)",$sum_results['PASSED'],$percent_results['PASSED']) . "\n".
934 "Time taken : " . sprintf("%4d seconds", $this->end_time
- $this->start_time
) . "\n".
937 $failed_test_summary = '';
938 if ($this->failed_tests
) {
939 $failed_test_summary .= "\n".$this->ddash
."\n".
940 "FAILED TEST SUMMARY\n".$this->sdash
."\n";
941 foreach ($this->failed_tests
as $failed_test_data) {
942 $failed_test_summary .= $failed_test_data['test_name'] . "\n";
944 $failed_test_summary .= $this->ddash
."\n";
947 if ($failed_test_summary && !$this->conf
['NO_PHPTEST_SUMMARY']) {
948 $this->writemsg($failed_test_summary);
951 /* We got failed Tests, offer the user to send and e-mail to QA team, unless NO_INTERACTION is set */
952 if ($sum_results['FAILED'] && !$this->conf
['NO_INTERACTION']) {
953 $fp = fopen("php://stdin", "r+");
954 $this->writemsg("\nPlease allow this report to be send to the PHP QA\nteam. This will give us a better understanding in how\n");
955 $this->writemsg("PHP's test cases are doing.\n");
956 $this->writemsg("(choose \"s\" to just save the results to a file)? [Yns]: ");
958 $user_input = fgets($fp, 10);
959 $just_save_results = (strtolower($user_input[0]) == 's');
961 if ($just_save_results ||
strlen(trim($user_input)) == 0 ||
strtolower($user_input[0]) == 'y') {
963 * Collect information about the host system for our report
964 * Fetch phpinfo() output so that we can see the PHP enviroment
965 * Make an archive of all the failed tests
969 /* Ask the user to provide an email address, so that QA team can contact the user */
970 if (!strncasecmp($user_input, 'y', 1) ||
strlen(trim($user_input)) == 0) {
971 echo "\nPlease enter your email address.\n(Your address will be mangled so that it will not go out on any\nmailinglist in plain text): ";
973 $fp = fopen("php://stdin", "r+");
974 $user_email = trim(fgets($fp, 1024));
975 $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email));
978 $failed_tests_data = '';
979 $sep = "\n" . str_repeat('=', 80) . "\n";
981 $failed_tests_data .= $failed_test_summary . "\n";
983 if (array_sum($this->failed_tests
)) {
984 foreach ($this->failed_tests
as $test_info) {
985 $failed_tests_data .= $sep . $test_info['name'];
986 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output']));
987 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff']));
988 $failed_tests_data .= $sep . "\n\n";
995 $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep;
996 $failed_tests_data .= "OS:\n". PHP_OS
. "\n\n";
997 $automake = $autoconf = $libtool = $compiler = 'N/A';
999 if (!$this->iswin32
) {
1000 $automake = shell_exec('automake --version');
1001 $autoconf = shell_exec('autoconf --version');
1002 /* Always use the generated libtool - Mac OSX uses 'glibtool' */
1003 $libtool = shell_exec('./libtool --version');
1004 /* Try the most common flags for 'version' */
1005 $flags = array('-v', '-V', '--version');
1007 foreach($flags AS $flag) {
1008 system($this->env
['CC']." $flag >/dev/null 2>&1", $cc_status);
1009 if($cc_status == 0) {
1010 $compiler = shell_exec($this->env
['CC']." $flag 2>&1");
1016 $failed_tests_data .= "Automake:\n$automake\n";
1017 $failed_tests_data .= "Autoconf:\n$autoconf\n";
1018 $failed_tests_data .= "Libtool:\n$libtool\n";
1019 $failed_tests_data .= "Compiler:\n$compiler\n";
1020 $failed_tests_data .= "Bison:\n". @shell_exec
('bison --version'). "\n";
1021 $failed_tests_data .= "\n\n";
1023 if (isset($user_email)) {
1024 $failed_tests_data .= "User's E-mail: ".$user_email."\n\n";
1027 $failed_tests_data .= $sep . "PHPINFO" . $sep;
1028 $failed_tests_data .= shell_exec($this->conf
['TEST_PHP_EXECUTABLE'].' -dhtml_errors=0 -i');
1032 if ($just_save_results ||
1033 !post_result_data("status=$status&version=".urlencode(TESTED_PHP_VERSION
),$failed_tests_data)) {
1034 $output_file = 'php_test_results_' . date('Ymd_Hi') . ( $compression ?
'.txt.gz' : '.txt' );
1035 $fp = fopen($output_file, "w");
1036 fwrite($fp, $failed_tests_data);
1039 if (!$just_save_results)
1040 echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n";
1041 echo "Please send ".$output_file." to ".PHP_QA_EMAIL
." manually, thank you.\n";
1043 fwrite($fp, "\nThank you for helping to make PHP better.\n");
1049 if($this->conf
['REPORT_EXIT_STATUS'] and $sum_results['FAILED']) {
1054 function getINISettings(&$section_text)
1056 $ini_settings = $this->ini_overwrites
;
1057 // Any special ini settings
1058 // these may overwrite the test defaults...
1059 if (array_key_exists('INI', $section_text)) {
1060 settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings);
1062 return $ini_settings;
1065 function getINIParams(&$section_text)
1067 if (!$section_text) return '';
1068 // XXX php5 current has a problem doing this in one line
1069 // it fails with Only variables can be passed by reference
1070 // on test ext\calendar\tests\jdtojewish.phpt
1071 // return settings2params($this->getINISettings($section_text));
1072 $ini = $this->getINISettings($section_text);
1073 return settings2params($ini);
1076 function calculateDocumentRoot()
1078 if ($this->conf
['TEST_WEB'] ||
$this->test_executable_iscgi
) {
1079 // configure DOCUMENT_ROOT for web tests
1080 // this assumes that directories from the base url
1081 // matches directory depth from the base path
1082 $parts = parse_url($this->conf
['TEST_WEB_BASE_URL']);
1083 $depth = substr_count($parts['path'],'/');
1084 $docroot = $this->conf
['TEST_BASE_PATH'];
1085 for ($i=0 ; $i < $depth; $i++
) $docroot = dirname($docroot);
1086 $this->conf
['TEST_DOCUMENT_ROOT']=$docroot;
1087 $this->conf
['TEST_BASE_SCRIPT_NAME']=$parts['path'];
1088 $this->conf
['TEST_SERVER_URL']=substr($this->conf
['TEST_WEB_BASE_URL'],0,strlen($this->conf
['TEST_WEB_BASE_URL'])-strlen($parts['path']));
1090 $this->conf
['TEST_DOCUMENT_ROOT']='';
1091 $this->conf
['TEST_BASE_SCRIPT_NAME']='';
1092 $this->conf
['TEST_SERVER_URL']='';
1096 function evalSettings($filename,$data) {
1097 // we eval the section so we can allow dynamic env vars
1099 $filename = str_replace('\\','/',$filename);
1100 $cwd = str_replace('\\','/',$this->cwd
);
1101 $filepath = dirname($filename);
1102 $scriptname = substr($filename,strlen($this->conf
['TEST_DOCUMENT_ROOT']));
1103 // eval fails if no newline
1104 return eval("$data\n");
1107 function getENVSettings(&$section_text,$testfile)
1110 // Any special environment settings
1111 // these may overwrite the test defaults...
1112 if (array_key_exists('ENV', $section_text)) {
1113 $sect = $this->evalSettings($testfile,$section_text['ENV']);
1114 //print "data evaled:\n$sect\n";
1115 settings2array(preg_split( "/[\n\r]+/", $sect), $env);
1120 function getEvalTestSettings($section_text,$testfile)
1123 // Any special environment settings
1124 // these may overwrite the test defaults...
1125 if ($section_text) {
1126 $sect = $this->evalSettings($testfile,$section_text);
1127 //print "data evaled:\n$sect\n";
1128 settings2array(preg_split( "/[\n\r]+/", $sect), $rq);
1134 // Load the sections of the test file.
1136 function getSectionText($file)
1138 // Load the sections of the test file.
1139 $section_text = array(
1140 'TEST' => '(unnamed test)',
1145 '_DIR' => realpath(dirname($file)),
1148 $fp = @fopen
($file, "r")
1149 or $this->error("Cannot open test file: $file");
1152 while (!feof($fp)) {
1154 // Match the beginning of a section.
1155 if (ereg('^--([A-Z]+)--',$line,$r)) {
1157 $section_text[$section] = '';
1161 // Add to the section text.
1162 $section_text[$section] .= $line;
1165 foreach ($section_text as $k=>$v) {
1166 // for POST data ,we only want to trim the last new line!
1167 if ($k == 'POST' && preg_match('/^(.*?)\r?\n$/Ds',$v,$matches)) {
1168 $section_text[$k]=$matches[1];
1170 $section_text[$k]=trim($v);
1173 return $section_text;
1177 // Check if test should be skipped.
1179 function getSkipReason($file,&$section_text,$docgi=false)
1181 // if the test uses POST or GET, and it's not the cgi
1183 if ($docgi && !$this->conf
['TEST_WEB'] && !$this->test_executable_iscgi
) {
1184 $this->showstatus($section_text['TEST'], 'SKIPPED', 'CGI Test needs CGI Binary');
1187 // if we're doing web testing, then we wont be able to set
1188 // ini setting on the command line. be sure the executables
1189 // ini settings are compatible with the test, or skip
1190 if (($docgi ||
$this->conf
['TEST_WEB']) &&
1191 isset($section_text['INI']) && $section_text['INI']) {
1192 $settings = $this->getINISettings($section_text);
1193 foreach ($settings as $k=>$v) {
1194 if (strcasecmp($v,'off')==0 ||
!$v) $v='';
1195 $haveval = isset($this->inisettings
[$k]['local_value']);
1196 if ($k == 'include_path') {
1197 // we only want to know that src directory
1198 // is in the include path
1199 if (strpos($this->inisettings
[$k]['local_value'],$this->cwd
))
1202 if (($haveval && $this->inisettings
[$k]['local_value'] != $v) ||
(!$haveval && $v)) {
1203 $this->showstatus($section_text['TEST'], 'SKIPPED', "Test requires ini setting $k=[$v], not [".($haveval?
$this->inisettings
[$k]['local_value']:'')."]");
1208 // now handle a SKIPIF section
1209 if ($section_text['SKIPIF']) {
1210 $output = trim($this->runscript($section_text['SKIPIF'],$this->test_executable_iscgi
,realpath(dirname($file))),true);
1211 if (!$output) return NULL;
1212 if ($this->conf
['TEST_PHP_DETAILED'] > 2)
1213 print "SKIPIF: [$output]\n";
1214 if (eregi("^skip", $output)){
1216 $reason = (ereg("^skip[[:space:]]*(.+)\$", $output)) ?
ereg_replace("^skip[[:space:]]*(.+)\$", "\\1", $output) : FALSE;
1217 $this->showstatus($section_text['TEST'], 'SKIPPED', $reason);
1220 if (eregi("^info", $output)) {
1221 $reason = (ereg("^info[[:space:]]*(.+)\$", $output)) ?
ereg_replace("^info[[:space:]]*(.+)\$", "\\1", $output) : FALSE;
1223 $tested .= " (info: $reason)";
1231 // Run an individual test case.
1233 function run_test($file)
1235 if ($this->conf
['TEST_PHP_DETAILED'])
1236 $this->writemsg("\n=================\nTEST $file\n");
1238 $section_text = $this->getSectionText($file);
1241 $shortname = str_replace($this->conf
['TEST_BASE_PATH'].'\\', '', $file);
1243 $shortname = str_replace($this->conf
['TEST_BASE_PATH'].'/', '', $file);
1244 $tested = $section_text['TEST']." [$shortname]";
1246 if ($this->conf
['TEST_WEB']) {
1247 $tmp_file = ereg_replace('\.phpt$','.'.$this->conf
['TEST_WEB_EXT'],$file);
1248 $uri = $this->conf
['TEST_BASE_SCRIPT_NAME'].str_replace($this->conf
['TEST_BASE_PATH'], '', $tmp_file);
1249 $uri = str_replace('\\', '/', $uri);
1251 $tmp_file = ereg_replace('\.phpt$','.php',$file);
1255 // unlink old test results
1256 @unlink
(ereg_replace('\.phpt$','.diff',$file));
1257 @unlink
(ereg_replace('\.phpt$','.log',$file));
1258 @unlink
(ereg_replace('\.phpt$','.exp',$file));
1259 @unlink
(ereg_replace('\.phpt$','.out',$file));
1261 if (!$this->conf
['TEST_WEB']) {
1262 // Reset environment from any previous test.
1263 $env = $this->getENVSettings($section_text,$tmp_file);
1264 $ini_overwrites = $this->getINIParams($section_text);
1267 // if this is a cgi test, prepare for it
1269 $havepost = array_key_exists('POST', $section_text) && !empty($section_text['POST']);
1270 // allow empty query_string requests
1271 $haveget = array_key_exists('GET', $section_text) && !empty($section_text['GET']);
1272 $do_cgi = array_key_exists('CGI', $section_text) ||
$haveget ||
$havepost;
1274 $skipreason = $this->getSkipReason($file,$section_text,$do_cgi);
1275 if ($skipreason == 'SKIPPED') {
1279 // We've satisfied the preconditions - run the test!
1280 file_put_contents($tmp_file,$section_text['FILE']);
1286 if ($this->conf
['TEST_WEB']) {
1287 $request = $this->getEvalTestSettings(@$section_text['REQUEST'],$tmp_file);
1288 $headers = $this->getEvalTestSettings(@$section_text['HEADERS'],$tmp_file);
1290 $method = isset($request['method'])?
$request['method']:$havepost?
'POST':'GET';
1291 $query_string = $haveget?
$section_text['GET']:'';
1294 $options['method']=$method;
1295 if (isset($this->conf
['timeout'])) $options['timeout'] = $this->conf
['timeout'];
1296 if (isset($this->conf
['proxy_host'])) $options['proxy_host'] = $this->conf
['proxy_host'];
1297 if (isset($this->conf
['proxy_port'])) $options['proxy_port'] = $this->conf
['proxy_port'];
1298 if (isset($this->conf
['proxy_user'])) $options['proxy_user'] = $this->conf
['proxy_user'];
1299 if (isset($this->conf
['proxy_pass'])) $options['proxy_pass'] = $this->conf
['proxy_pass'];
1301 $post = $havepost?
$section_text['POST']:NULL;
1302 $url = $this->conf
['TEST_SERVER_URL'];
1303 if (isset($request['SCRIPT_NAME']))
1304 $url .= $request['SCRIPT_NAME'];
1307 if (isset($request['PATH_INFO']))
1308 $url .= $request['PATH_INFO'];
1309 if (isset($request['FRAGMENT']))
1310 $url .= '#'.$request['FRAGMENT'];
1311 if (isset($request['QUERY_STRING']))
1312 $query_string = $request['QUERY_STRING'];
1314 $url .= '?'.$query_string;
1315 if ($this->conf
['TEST_PHP_DETAILED'])
1316 $this->writemsg("\nURL = $url\n");
1317 } else if ($do_cgi) {
1318 $query_string = $haveget?
$section_text['GET']:'';
1320 if (!array_key_exists('GATEWAY_INTERFACE', $env))
1321 $env['GATEWAY_INTERFACE']='CGI/1.1';
1322 if (!array_key_exists('SERVER_SOFTWARE', $env))
1323 $env['SERVER_SOFTWARE']='PHP Test Harness';
1324 if (!array_key_exists('SERVER_SOFTWARE', $env))
1325 $env['SERVER_NAME']='127.0.0.1';
1326 if (!array_key_exists('REDIRECT_STATUS', $env))
1327 $env['REDIRECT_STATUS']='200';
1328 if (!array_key_exists('SERVER_NAME', $env))
1329 $env['QUERY_STRING']=$query_string;
1330 if (!array_key_exists('PATH_TRANSLATED', $env) &&
1331 !array_key_exists('SCRIPT_FILENAME', $env)) {
1332 $env['PATH_TRANSLATED']=$tmp_file;
1333 $env['SCRIPT_FILENAME']=$tmp_file;
1335 if (!array_key_exists('PATH_TRANSLATED', $env))
1336 $env['PATH_TRANSLATED']='';
1337 if (!array_key_exists('PATH_INFO', $env))
1338 $env['PATH_INFO']='';
1339 if (!array_key_exists('SCRIPT_NAME', $env))
1340 $env['SCRIPT_NAME']='';
1341 if (!array_key_exists('SCRIPT_FILENAME', $env))
1342 $env['SCRIPT_FILENAME']='';
1344 if (array_key_exists('POST', $section_text) && (!$haveget ||
!empty($section_text['POST']))) {
1345 $post = $section_text['POST'];
1346 $content_length = strlen($post);
1347 if (!array_key_exists('REQUEST_METHOD', $env))
1348 $env['REQUEST_METHOD']='POST';
1349 if (!array_key_exists('CONTENT_TYPE', $env))
1350 $env['CONTENT_TYPE']='application/x-www-form-urlencoded';
1351 if (!array_key_exists('CONTENT_LENGTH', $env))
1352 $env['CONTENT_LENGTH']=$content_length;
1354 if (!array_key_exists('REQUEST_METHOD', $env))
1355 $env['REQUEST_METHOD']='GET';
1356 if (!array_key_exists('CONTENT_TYPE', $env))
1357 $env['CONTENT_TYPE']='';
1358 if (!array_key_exists('CONTENT_LENGTH', $env))
1359 $env['CONTENT_LENGTH']='';
1361 if ($this->conf
['TEST_PHP_DETAILED'] > 1)
1362 $this->writemsg("\nCONTENT_LENGTH = " . $env['CONTENT_LENGTH'] .
1363 "\nCONTENT_TYPE = " . $env['CONTENT_TYPE'] .
1364 "\nPATH_TRANSLATED = " . $env['PATH_TRANSLATED'] .
1365 "\nPATH_INFO = " . $env['PATH_INFO'] .
1366 "\nQUERY_STRING = " . $env['QUERY_STRING'] .
1367 "\nREDIRECT_STATUS = " . $env['REDIRECT_STATUS'] .
1368 "\nREQUEST_METHOD = " . $env['REQUEST_METHOD'] .
1369 "\nSCRIPT_NAME = " . $env['SCRIPT_NAME'] .
1370 "\nSCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . "\n");
1371 /* not cgi spec to put query string on command line,
1372 but used by a couple tests to catch a security hole
1373 in older php versions. At least IIS can be configured
1375 $args = $env['QUERY_STRING'];
1376 $args = "$ini_overwrites $tmp_file \"$args\" 2>&1";
1378 $args = $section_text['ARGS'] ?
$section_text['ARGS'] : '';
1379 $args = "$ini_overwrites $tmp_file $args 2>&1";
1382 if ($this->conf
['TEST_WEB']) {
1383 // we want headers also, so fopen
1384 $r = new HTTPRequest($url,$headers,$options,$post);
1385 //$out = preg_replace("/\r\n/","\n",$r->response);
1386 $out = $r->response
;
1387 $headers = $r->response_headers
;
1388 //print $r->outgoing_payload."\n";
1389 //print $r->incoming_payload."\n";
1391 $out = execute($this->conf
['TEST_PHP_EXECUTABLE'],$args,$post,$this->cwd
,$env);
1392 // if this is a cgi, remove the headers first
1393 if ($this->test_executable_iscgi
1394 && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
1396 $rh = preg_split("/[\n\r]+/",$match[1]);
1398 foreach ($rh as $line) {
1399 if (strpos($line, ':')!==false) {
1400 $line = explode(":", $line, 2);
1401 $headers[trim($line[0])] = trim($line[1]);
1407 if ($this->conf
['TEST_PHP_DETAILED'] > 2) {
1410 echo "OUTPUT: \n$out\n";
1414 // Does the output match what is expected?
1415 $output = trim($out);
1416 $output = preg_replace('/\r\n/',"\n",$output);
1420 if (isset($section_text['EXPECTF']) ||
isset($section_text['EXPECTREGEX'])) {
1421 if (isset($section_text['EXPECTF'])) {
1422 $wanted = $section_text['EXPECTF'];
1424 $wanted = $section_text['EXPECTREGEX'];
1426 $wanted_re = preg_replace('/\r\n/',"\n",$wanted);
1427 if (isset($section_text['EXPECTF'])) {
1428 $wanted_re = preg_quote($wanted_re, '/');
1430 $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy
1431 $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re);
1432 $wanted_re = str_replace("%d", "[0-9]+", $wanted_re);
1433 $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re);
1434 $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re);
1435 $wanted_re = str_replace("%c", ".", $wanted_re);
1436 // %f allows two points "-.0.0" but that is the best *simple* expression
1438 /* DEBUG YOUR REGEX HERE
1439 var_dump($wanted_re);
1440 print(str_repeat('=', 80) . "\n");
1443 $failed = !preg_match("/^$wanted_re\$/s", $output);
1446 $skipexpect = false;
1447 if (!$failed && $this->conf
['TEST_WEB'] && isset($section_text['EXPECTHEADERS'])) {
1449 $lines = preg_split("/[\n\r]+/",$section_text['EXPECTHEADERS']);
1451 foreach ($lines as $line) {
1452 if (strpos($line, ':')!==false) {
1453 $line = explode(":", $line, 2);
1454 $want[trim($line[0])] = trim($line[1]);
1455 $wanted .= trim($line[0]).': '.trim($line[1])."\n";
1459 foreach ($want as $k=>$v) {
1460 $output .= "$k: {$headers[$k]}\n";
1461 if (!isset($headers[$k]) ||
$headers[$k] != $v) {
1466 // different servers may do different things on non-200 results
1467 // for instance, IIS will deliver it's own error pages, so we
1468 // cannot expect to match up the EXPECT section. We may however,
1469 // want to match EXPECT on more than 200 results, so this may
1470 // need to change later.
1471 $skipexpect = isset($headers['Status']) && $headers['Status'] != 200;
1474 if (!$failed && !$skipexpect && isset($section_text['EXPECT'])) {
1475 $wanted = $section_text['EXPECT'];
1476 $wanted = preg_replace('/\r\n/',"\n",$wanted);
1477 $failed = (0 != strcmp($output,$wanted));
1482 $this->showstatus($tested, 'PASSED');
1486 // Test failed so we need to report details.
1487 $this->showstatus($tested, 'FAILED');
1489 $this->failed_tests
[] = array(
1491 'test_name' => $tested,
1492 'output' => ereg_replace('\.phpt$','.log', $file),
1493 'diff' => ereg_replace('\.phpt$','.diff', $file)
1496 if ($this->conf
['TEST_PHP_DETAILED'])
1497 $this->writemsg(generate_diff($wanted,$output)."\n");
1500 if (strpos($this->conf
['TEST_PHP_LOG_FORMAT'],'E') !== FALSE) {
1501 $logname = ereg_replace('\.phpt$','.exp',$file);
1502 file_put_contents($logname,$wanted);
1506 if (strpos($this->conf
['TEST_PHP_LOG_FORMAT'],'O') !== FALSE) {
1507 $logname = ereg_replace('\.phpt$','.out',$file);
1508 file_put_contents($logname,$output);
1512 if (strpos($this->conf
['TEST_PHP_LOG_FORMAT'],'D') !== FALSE) {
1513 $logname = ereg_replace('\.phpt$','.diff',$file);
1514 file_put_contents($logname,generate_diff($wanted,$output));
1518 if (strpos($this->conf
['TEST_PHP_LOG_FORMAT'],'L') !== FALSE) {
1519 $logname = ereg_replace('\.phpt$','.log',$file);
1520 file_put_contents($logname,
1521 "\n---- EXPECTED OUTPUT\n$wanted\n".
1522 "---- ACTUAL OUTPUT\n$output\n".
1524 // display emacs/msvc error output
1525 if (strpos($this->conf
['TEST_PHP_LOG_FORMAT'],'C') !== FALSE) {
1526 $this->error_report($file,$logname,$tested);
1533 // Write an error in a format recognizable to Emacs or MSVC.
1535 function error_report($testname,$logname,$tested)
1537 $testname = realpath($testname);
1538 $logname = realpath($logname);
1539 switch ($this->conf
['TEST_PHP_ERROR_STYLE']) {
1542 $this->writemsg($testname . "(1) : $tested\n");
1543 $this->writemsg($logname . "(1) : $tested\n");
1546 $this->writemsg($testname . ":1: $tested\n");
1547 $this->writemsg($logname . ":1: $tested\n");
1552 function error($message)
1554 $this->writemsg("ERROR: {$message}\n");
1559 $test = new testHarness();
1565 * vim600: fdm=marker
1566 * vim: noet sw=4 ts=4