cvs: php4 / README.TESTING2 run-tests-config.php run-tests2.php /sapi/tests test001.phpt test002.phpt test003.phpt test004.phpt test005.phpt
test006.phpt test007.phpt

From: Date: Tue, 25 Mar 2003 07:45:18 +0000
Subject: cvs: php4 / README.TESTING2 run-tests-config.php run-tests2.php /sapi/tests test001.phpt test002.phpt test003.phpt test004.phpt test005.phpt
test006.phpt test007.phpt
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-19762@lists.php.net to get a copy of this message
shane Tue Mar 25 02:45:18 2003 EDT Added files: /php4 README.TESTING2 run-tests-config.php /php4/sapi/tests test001.phpt test002.phpt test003.phpt test004.phpt test005.phpt test006.phpt test007.phpt Modified files: /php4 run-tests2.php Log: many new enhancements to run-tests that allow for testing cgi and other sapi modules via http. see README.TESTING2 for more details several sapi tests added

Index: php4/run-tests2.php diff -u php4/run-tests2.php:1.7 php4/run-tests2.php:1.8 --- php4/run-tests2.php:1.7 Tue Mar 18 07:05:58 2003 +++ php4/run-tests2.php Tue Mar 25 02:45:18 2003 @@ -16,31 +16,429 @@ | Authors: Ilia Alshanetsky <ilia@php.net> | | Preston L. Bannister <pbannister@php.net> | | Marcus Boerger <helly@php.net> | + | Shane Caraveo <shane@php.net> | | Derick Rethans <derick@php.net> | | Sander Roobol <sander@php.net> | - | John Coggeshall <john@php.net> | | (based on version by: Stig Bakken <ssb@php.net>) | | (based on the PHP 3 test framework by Rasmus Lerdorf) | +----------------------------------------------------------------------+ */ + set_time_limit(0); -ob_implicit_flush(); +while(@ob_end_clean()); +if (ob_get_level()) echo "Not all buffers were deleted.\n"; error_reporting(E_ALL); -define('PHP_QA_EMAIL', 'php-qa@lists.php.net'); + +/********************************************************************** + * QA configuration + */ + +define('PHP_QA_EMAIL', 'qa-reports@lists.php.net'); define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php'); +/********************************************************************** + * error messages + */ + +define('PCRE_MISSING_ERROR', +'+-----------------------------------------------------------+ +| ! ERROR ! | +| The test-suite requires that you have pcre extension | +| enabled. To enable this extension either compile your PHP | +| with --with-pcre-regex or if you have compiled pcre as a | +| shared module load it via php.ini. | ++-----------------------------------------------------------+'); +define('SAFE_MODE_WARNING', +'+-----------------------------------------------------------+ +| ! WARNING ! | +| You are running the test-suite with "safe_mode" ENABLED ! | +| | +| Chances are high that no test will work at all, | +| depending on how you configured "safe_mode" ! | ++-----------------------------------------------------------+'); +define('TMP_MISSING', +'+-----------------------------------------------------------+ +| ! ERROR ! | +| You must create /tmp for session tests to work! | +| | ++-----------------------------------------------------------+'); +define('PROC_OPEN_MISSING', +'+-----------------------------------------------------------+ +| ! ERROR ! | +| The test-suite requires that proc_open() is available. | +| Please check if you disabled it in php.ini. | ++-----------------------------------------------------------+'); +define('REQ_PHP_VERSION', +'+-----------------------------------------------------------+ +| ! ERROR ! | +| The test-suite must be run with PHP 5 or later. | +| You can still test older extecutables by setting | +| TEST_PHP_EXECUTABLE and running this script with PHP 5. | ++-----------------------------------------------------------+'); +/********************************************************************** + * information scripts + */ +define('PHP_INFO_SCRIPT','<?php echo " +PHP_SAPI=" . PHP_SAPI . " +PHP_VERSION=" . phpversion() . " +ZEND_VERSION=" . zend_version() . " +PHP_OS=" . PHP_OS . " +INCLUDE_PATH=" . get_cfg_var("include_path") . " +INI=" . realpath(get_cfg_var("cfg_file_path")) . " +SCANNED_INI=" . (function_exists(\'php_ini_scanned_files\') ? + str_replace("\n","", php_ini_scanned_files()) : + "** not determined **") . " +SERVER_SOFTWARE=" . $_ENV[\'SERVER_SOFTWARE\']; +?>'); + +define('PHP_EXTENSIONS_SCRIPT','<?php print join(get_loaded_extensions(),":"); ?>'); +define('PHP_INI_SETTINGS_SCRIPT','<?php echo serialize(ini_get_all()); ?>'); + +/********************************************************************** + * various utility functions + */ + +function save_to_file($filename,$text) +{ + $fp = @fopen($filename,'w') + or die("Cannot open file '" . $filename . "' (save_to_file)"); + fwrite($fp,$text); + fclose($fp); +} + +function settings2array($settings, &$ini_settings) +{ + foreach($settings as $setting) { + if (strpos($setting, '=')!==false) { + $setting = explode("=", $setting, 2); + $name = trim($setting[0]); + $value = trim($setting[1]); + $ini_settings[$name] = $value; + } + } +} + +function settings2params(&$ini_settings) +{ + $settings = ''; + if (count($ini_settings)) { + foreach($ini_settings as $name => $value) { + $value = addslashes($value); + $settings .= " -d \"".strtolower($name)."=$value\""; + } + } + return $settings; +} + +function generate_diff($wanted,$output) +{ + $w = explode("\n", $wanted); + $o = explode("\n", $output); + $w1 = array_diff_assoc($w,$o); + $o1 = array_diff_assoc($o,$w); + $w2 = array(); + $o2 = array(); + foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1).$val; + foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1).$val; + $diff = array_merge($w2, $o2); + ksort($diff); + return implode("\r\n", $diff); +} + +function mkpath($path,$mode = 0700) { + $dirs = split('[\\|/]',realpath($path)); + $path = $dirs[0]; + for($i = 1;$i < count($dirs);$i++) { + $path .= '/'.$dirs[$i]; + @mkdir($path,$mode); + } +} + +function copyfiles($src,$new) { + $d = dir($src); + while (($entry = $d->read())) { + if (is_file("$src/$entry")) + copy("$src/$entry","$new/$entry"); + } + $d->close(); +} + +function post_result_data($query,$data) +{ + $url = QA_SUBMISSION_PAGE.'?'.$query; + $post = "php_test_data=" . urlencode(base64_encode(preg_replace("/[\\x00]/", "[0x0]", $data))); + $r = new HTTPRequest($url,NULL,NULL,$post); + return $this->response_headers['Status']=='200'; +} + + +function execute($command, $args=NULL, $input=NULL, $cwd=NULL, $env=NULL) +{ + $data = ""; + + if (gettype($args)=='array') { + $args = join($args,' '); + } + $commandline = "$command $args"; + $proc = proc_open($commandline, array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w')), + $pipes, $cwd, $env); + + if (!$proc) + return false; + + if ($input) { + $out = fwrite($pipes[0],$input); + if ($out != strlen($input)) { + return NULL; + } + } + + fclose($pipes[0]); + + while (true) { + /* hide errors from interrupted syscalls */ + $r = $pipes; + $w = null; + $e = null; + $n = @stream_select($r, $w, $e, 60); + + if ($n == 0) { + /* timed out */ + $data .= "\n ** ERROR: process timed out **\n"; + proc_terminate($proc); + return $data; + } else if ($n) { + $line = fread($pipes[1], 8192); + if (strlen($line) == 0) { + /* EOF */ + break; + } + $data .= $line; + } + } + $code = proc_close($proc); + return $data; +} + +function executeCode($php, $ini_overwrites, $code, $remove_headers=true, $cwd=NULL, $env=NULL) +{ + $params = NULL; + if ($ini_overwrites) { + $info_params = array(); + settings2array($ini_overwrites,$info_params); + $params = settings2params($info_params); + } + $out = execute($php, $params, $code, $cwd, $env); + // kill the headers + if ($remove_headers && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) { + $out = $match[2]; + } + return $out; +} + + +/********************************************************************** + * a simple request class that lets us handle http based tests + */ + +class HTTPRequest +{ + var $headers = array(); + var $timeout = 4; + var $urlparts = NULL; + var $url = ''; + var $userAgent = 'PHP-Test-Harness'; + var $options = array(); + var $postdata = NULL; + var $errmsg = ''; + var $errno = 0; + var $response; + var $response_headers; + var $outgoing_payload; + var $incoming_payload = ''; + + /* + URL is the full url + headers is assoc array of outgoing http headers + + options may include + timeout + proxy_host + proxy_port + proxy_user + proxy_pass + method (GET|POST) + + post data is, well, post data. It is not processed so + multipart stuff must be prepared before calling this + (or add it to class) + */ + function HTTPRequest($URL, $headers=array(), $options=array(), $postdata=NULL) + { + $this->urlparts = @parse_url($URL); + $this->url = $URL; + $this->options = $options; + $this->headers = $headers; + $this->postdata = &$postdata; + $this->doRequest(); + } + + function doRequest() + { + if (!$this->_validateUrl()) return; + + if (isset($this->options['timeout'])) + $this->timeout = (int)$this->options['timeout']; + + $this->_sendHTTP(); + } + + function _validateUrl() + { + if ( ! is_array($this->urlparts) ) { + return FALSE; + } + if (!isset($this->urlparts['host'])) { + $this->urlparts['host']='127.0.0.1'; + } + if (!isset($this->urlparts['port'])) { + $this->urlparts['port'] = 80; + } + if (!isset($this->urlparts['path']) || !$this->urlparts['path']) + $this->urlparts['path'] = '/'; + return TRUE; + } + + function _parseResponse() + { + if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $this->incoming_payload, $match)) { + $this->response = $match[2]; + if (preg_match("/^HTTP\/1\.. (\d+).*/s",$match[1],$status) && !$status[1]) { + $this->errmsg = "HTTP Response $status[1] Not Found"; + return FALSE; + } + $rh = preg_split("/[\n\r]+/",$match[1]); + $this->response_headers = array(); + foreach ($rh as $line) { + if (strpos($line, ':')!==false) { + $line = explode(":", $line, 2); + $this->response_headers[trim($line[0])] = trim($line[1]); + } + } + $this->response_headers['Status']=$status[1]; + // if no content, return false + if(strlen($this->response) > 0) return TRUE; + } + $this->errmsg = 'Invalid HTTP Response'; + return FALSE; + } + + function &_getRequest() + { + $fullpath = $this->urlparts['path']. + (isset($this->urlparts['query'])?'?'.$this->urlparts['query']:''). + (isset($this->urlparts['fragment'])?'#'.$this->urlparts['fragment']:''); + if (isset($this->options['proxy_host'])) { + $fullpath = 'http://'.$this->urlparts['host'].':'.$this->urlparts['port'].$fullpath; + } + if (isset($this->options['proxy_user'])) { + $headers['Proxy-Authorization'] = 'Basic ' . base64_encode($this->options['proxy_user'].":".$this->options['proxy_pass']); + } + $headers['User-Agent'] = $this->userAgent; + $headers['Host'] = $this->urlparts['host']; + $headers['Content-Length'] = strlen($this->postdata); + $headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (isset($this->headers)) { + $headers = array_merge($headers, $this->headers); + } + $headertext = ''; + foreach ($headers as $k => $v) { + $headertext .= "$k: $v\r\n"; + } + $method = trim($this->options['method'])?strtoupper(trim($this->options['method'])):'GET'; + $this->outgoing_payload = + "$method $fullpath HTTP/1.0\r\n". + $headertext."\r\n". + $this->postdata; + return $this->outgoing_payload; + } + + function &_sendHTTP() + { + $this->_getRequest(); + $host = $this->urlparts['host']; + $port = $this->urlparts['port']; + if (isset($this->options['proxy_host'])) { + $host = $this->options['proxy_host']; + $port = isset($this->options['proxy_port'])?$this->options['proxy_port']:8080; + } + // send + if ($this->timeout > 0) { + $fp = fsockopen($host, $port, $this->errno, $this->errmsg, $this->timeout); + } else { + $fp = fsockopen($host, $port, $this->errno, $this->errmsg); + } + if (!$fp) { + $this->errmsg = "Connect Error to $host:$port"; + return NULL; + } + if ($this->timeout > 0) { + // some builds of php do not support this, silence + // the warning + @socket_set_timeout($fp, $this->timeout); + } + if (!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { + $this->errmsg = "Error Sending Request Data to $host"; + return NULL; + } + + while ($data = fread($fp, 32768)) { + $this->incoming_payload .= $data; + } + + fclose($fp); + + $this->_parseResponse(); + } + +# a simple test case +#$r = new HTTPRequest('http://localhost:81/info.php/path/info'); +#print_r($r->response_headers); +#print $r->response; + +} // end HTTPRequest + + +/********************************************************************** + * main test harness + */ class testHarness { var $cwd; - var $TEST_PHP_SRCDIR; - var $TEST_PHP_EXECUTABLE; - var $TEST_PHP_LOG_FORMAT; - var $TEST_PHP_DETAILED; - var $TEST_PHP_ERROR_STYLE; - var $REPORT_EXIT_STATUS; - var $NO_PHPTEST_SUMMARY; - var $NO_INTERACTION; + var $xargs = array( + #arg env var value default description + 'c' => array('' ,'file' ,NULL ,'configuration file, see run-tests-config.php for example'), + 'd' => array('TEST_PATHS' ,'paths' ,NULL ,'colon seperate path list'), + 'e' => array('TEST_PHP_ERROR_STYLE','EMACS|MSVC' ,'EMACS' ,'editor error style'), + 'h' => array('' ,'' ,NULL ,'this help'), + 'i' => array('PHPRC' ,'path|file' ,NULL ,'ini file to use for tests (sets PHPRC)'), + 'l' => array('TEST_PHP_LOG_FORMAT' ,'string' ,'LEODC' ,'any combination of CDELO'), + 'm' => array('TEST_BASE_PATH' ,'path' ,NULL ,'copy tests to this path before testing'), + 'n' => array('NO_PHPTEST_SUMMARY' ,'' ,0 ,'do not print test summary'), + 'p' => array('TEST_PHP_EXECUTABLE' ,'path' ,NULL ,'php executable to be tested'), + 'q' => array('NO_INTERACTION' ,'' ,0 ,'no console interaction (ie dont contact QA)'), + 'r' => array('REPORT_EXIT_STATUS' ,'' ,0 ,'exit with status at end of execution'), + 's' => array('TEST_PHP_SRCDIR' ,'path' ,NULL ,'path to php source code'), + 't' => array('TEST_PHP_DETAILED' ,'number' ,0 ,'level of detail output to dump'), + 'u' => array('TEST_WEB_BASE_URL' ,'url' ,'' ,'base url for http testing'), + 'v' => array('TEST_CONTEXT_INFO' ,'' ,0 ,'view text executable context info'), + 'w' => array('TEST_WEB' ,'' ,0 ,'run tests via http'), + 'x' => array('TEST_WEB_EXT' ,'file ext' ,'php' ,'http file extension to use') + ); + var $conf = array(); var $test_to_run = array(); var $test_files = array(); var $test_results = array(); @@ -49,9 +447,13 @@ var $exts_tested = 0; var $exts_skipped = 0; var $ignored_by_ext = 0; - var $test_dirs = array('tests', 'pear', 'ext'); + var $test_dirs = array('tests', 'pear', 'ext', 'sapi'); var $start_time; var $end_time; + var $exec_info; + var $test_executable_iscgi = false; + var $inisettings; // the test executables settings, used for web tests + var $iswin32 = false; var $ddash = "====================================================================="; var $sdash = "---------------------------------------------------------------------"; @@ -79,36 +481,122 @@ 'auto_append_file'=>'', 'magic_quotes_runtime'=>'0', ); - var $env = array( - 'REDIRECT_STATUS'=>'', - 'QUERY_STRING'=>'', - 'PATH_TRANSLATED'=>'', - 'SCRIPT_FILENAME'=>'', - 'REQUEST_METHOD'=>'', - 'CONTENT_TYPE'=>'', - 'CONTENT_LENGTH'=>'', - ); + var $env = array(); var $info_params = array(); function testHarness() { - $this->checkPCRE(); - $this->checkSafeMode(); + $this->iswin32 = substr(PHP_OS, 0, 3) == "WIN"; + $this->checkRequirements(); + $this->env = $_ENV; $this->removeSensitiveEnvVars(); + $this->initializeConfiguration(); $this->parseArgs(); + $this->setTestPaths(); # change to working directory - if ($this->TEST_PHP_SRCDIR) { - @chdir($this->TEST_PHP_SRCDIR); + if ($this->conf['TEST_PHP_SRCDIR']) { + @chdir($this->conf['TEST_PHP_SRCDIR']); } $this->cwd = getcwd(); - $this->isExecutable(); + + if (!$this->conf['TEST_PHP_SRCDIR']) + $this->conf['TEST_PHP_SRCDIR'] = $this->cwd; + if (!$this->conf['TEST_BASE_PATH'] && $this->conf['TEST_PHP_SRCDIR']) + $this->conf['TEST_BASE_PATH'] = $this->conf['TEST_PHP_SRCDIR']; + if ($this->iswin32) { + $this->conf['TEST_PHP_SRCDIR'] = str_replace('/','\\',$this->conf['TEST_PHP_SRCDIR']); + $this->conf['TEST_BASE_PATH'] = str_replace('/','\\',$this->conf['TEST_BASE_PATH']); + } + + if (!$this->conf['TEST_WEB'] && !is_executable($this->conf['TEST_PHP_EXECUTABLE'])) { + $this->error("invalid PHP executable specified by TEST_PHP_EXECUTABLE = " . + $this->conf['TEST_PHP_EXECUTABLE']); + return false; + } + $this->getInstalledExtensions(); + $this->getExecutableInfo(); + $this->getExecutableIniSettings(); + $this->test_executable_iscgi = strncmp($this->exec_info['PHP_SAPI'],'cgi',3)==0; + $this->calculateDocumentRoot(); + + // add TEST_PHP_SRCDIR to the include path, this facilitates + // tests including files from src/tests + //$this->ini_overwrites['include_path'] = $this->cwd.($this->iswin32?';.;':':.:').$this->exec_info['INCLUDE_PATH']; + + $params = array(); + settings2array($this->ini_overwrites,$params); + $this->info_params = settings2params($params); + $this->contextHeader(); + if ($this->conf['TEST_CONTEXT_INFO']) return; $this->loadFileList(); + $this->moveTestFiles(); $this->run(); $this->summarizeResults(); } + function getExecutableIniSettings() + { + $out = $this->runscript(PHP_INI_SETTINGS_SCRIPT,true); + $this->inisettings = unserialize($out); + } + + function getExecutableInfo() + { + $out = $this->runscript(PHP_INFO_SCRIPT,true); + $out = preg_split("/[\n\r]+/",$out); + $info = array(); + foreach ($out as $line) { + if (strpos($line, '=')!==false) { + $line = explode("=", $line, 2); + $name = trim($line[0]); + $value = trim($line[1]); + $info[$name] = $value; + } + } + $this->exec_info = $info; + } + + function getInstalledExtensions() + { + // get the list of installed extensions + $out = $this->runscript(PHP_EXTENSIONS_SCRIPT,true); + $this->exts_to_test = split(":",$out); + sort($this->exts_to_test); + $this->exts_tested = count($this->exts_to_test); + } + + // if running local, calls executeCode, + // otherwise does an http request + function runscript($script,$removeheaders=false,$cwd=NULL) + { + if ($this->conf['TEST_WEB']) { + $pi = "/testscript.{$this->conf['TEST_WEB_EXT']}"; + if (!$cwd) $cwd = $this->conf['TEST_BASE_PATH']; + $tmp_file = "$cwd$pi"; + $pi = substr($cwd,strlen($this->conf['TEST_BASE_PATH'])).$pi; + $url = "{$this->conf['TEST_WEB_BASE_URL']}$pi"; + save_to_file($tmp_file,$script); + $fd = fopen($url, "rb"); + $out = ''; + if ($fd) { + while (!feof($fd)) + $out .= fread($fd, 8192); + fclose($fd); + } + #unlink($tmp_file); + if ($removeheaders && + preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $this->incoming_payload, $match)) { + return $match[2]; + } + return $out; + } else { + return executeCode($this->conf['TEST_PHP_EXECUTABLE'],$this->ini_overwrites, $script,$removeheaders,$cwd,$this->env); + } + } + + // Use this function to do any displaying of text, so that // things can be over-written as necessary. @@ -124,134 +612,130 @@ function showstatus($item, $status, $reason = '') { switch($status) { - case 'PASSED': - $this->writemsg("PASSED: $item ($reason)\n"); - break; - case 'FAILED': - $this->writemsg("FAILED: $item ($reason)\n"); - break; - case 'SKIPPED': - $this->writemsg("SKIPPED: $item ($reason)\n"); break; - } - } + function help() { - return "usage: php run-tests.php [options]\n". - " -d testpaths colon seperate path list\n". - " -s path to php sources\n". - " -p path to php executable to be tested\n". - " -l logformat LEOD\n". - " -t 0|1 detailed reporting\n". - " -e string error style\n". - " -r 0|1 report exit status\n". - " -n 0|1 print test summary\n". - " -i 0|1 console interaction\n". - " -h this help\n"; + $usage = "usage: php run-tests.php [options]\n"; + foreach ($this->xargs as $arg=>$arg_info) { + $usage .= sprintf(" -%s %-12s %s\n",$arg,$arg_info[1],$arg_info[3]); + } + return $usage; } function parseArgs() { global $argc; global $argv; + global $_SERVER; if (!isset($argv)) { $argv = $_SERVER['argv']; $argc = $_SERVER['argc']; } - if (!isset($argc) || $argc < 2) return; + $conf = NULL; for ($i=1; $i<$argc;) { if ($argv[$i][0] != '-') continue; $opt = $argv[$i++][1]; - $value = 0; + if (isset($value)) unset($value); if (@$argv[$i][0] != '-') { @$value = $argv[$i++]; } switch($opt) { - case 'd': - $this->test_dirs = array(); - $paths = split(':|;',$value); - foreach($paths as $path) { - $this->test_dirs[] = realpath($path); - } - break; - case 's': - $this->TEST_PHP_SRCDIR = $value; - break; - case 'p': - $this->TEST_PHP_EXECUTABLE = $value; - break; - case 'l': - $this->TEST_PHP_LOG_FORMAT = $value; - break; - case 't': - $this->TEST_PHP_DETAILED = $value; - break; - case 'e': - $this->TEST_PHP_ERROR_STYLE = strtoupper($value); - break; - case 'r': - $this->REPORT_EXIT_STATUS = $value; - break; - case 'n': - $this->NO_PHPTEST_SUMMARY = $value; - break; - case 'i': - $this->NO_INTERACTION = $value; - break; - case 'h': - print $this->help(); - exit(0); + case 'c': + /* TODO: Implement configuraiton file */ + include($value); + if (!isset($conf)) { + $this->writemsg("Invalid configuration file\n"); + exit(1); + } + $this->conf = array_merge($this->conf,$conf); + break; + case 'e': + $this->conf['TEST_PHP_ERROR_STYLE'] = strtoupper($value); + break; + case 'h': + print $this->help(); + exit(0); + default: + if ($this->xargs[$opt][1] && isset($value)) + $this->conf[$this->xargs[$opt][0]] = $value; + else if (!$this->xargs[$opt][1]) + $this->conf[$this->xargs[$opt][0]] = isset($value)?$value:1; + else + $this->error("Invalid argument setting for argument $opt, should be [{$this->xargs[$opt][1]}]\n"); + break; } } + + // set config into environment, this allows + // executed tests to find out about the test + // configurations. config file or args overwrite + // env var config settings + $this->env = array_merge($this->env,$this->conf); + if (!$this->conf['TEST_WEB'] && !$this->conf['TEST_PHP_EXECUTABLE']) { + $this->writemsg($this->help()); + exit(0); + } } - + function removeSensitiveEnvVars() { # delete sensitive env vars - putenv('SSH_CLIENT=deleted'); - putenv('SSH_AUTH_SOCK=deleted'); - putenv('SSH_TTY=deleted'); + $this->env['SSH_CLIENT']='deleted'; + $this->env['SSH_AUTH_SOCK']='deleted'; + $this->env['SSH_TTY']='deleted'; + } + + function setEnvConfigVar($name) + { + if (isset($this->env[$name])) { + $this->conf[$name] = $this->env[$name]; + } } function initializeConfiguration() { - # get config from environment - $this->TEST_PHP_SRCDIR = getenv('TEST_PHP_SRCDIR'); - $this->TEST_PHP_EXECUTABLE = getenv('TEST_PHP_EXECUTABLE'); - $this->TEST_PHP_LOG_FORMAT = getenv('TEST_PHP_LOG_FORMAT'); - if (!$this->TEST_PHP_LOG_FORMAT) $this->TEST_PHP_LOG_FORMAT = 'LEOD'; - $this->TEST_PHP_DETAILED = getenv('TEST_PHP_DETAILED'); - $this->TEST_PHP_ERROR_STYLE = strtoupper(getenv('TEST_PHP_ERROR_STYLE')); - $this->REPORT_EXIT_STATUS = getenv('REPORT_EXIT_STATUS'); - $this->NO_PHPTEST_SUMMARY = getenv('NO_PHPTEST_SUMMARY'); - $this->NO_INTERACTION = getenv('NO_INTERACTION'); + foreach ($this->xargs as $arg=>$arg_info) { + if ($arg_info[0]) { + # initialize the default setting + $this->conf[$arg_info[0]]=$arg_info[2]; + # get config from environment + $this->setEnvConfigVar($arg_info[0]); + } + } } - function getInstalledExtensions() + function setTestPaths() { - // get the list of installed extensions - $this->exts_to_test = get_loaded_extensions(); - $this->exts_tested = count($this->exts_to_test); - sort($this->exts_to_test); + // configure test paths from config file or command line + if (@$this->conf['TEST_PATHS']) { + $this->test_dirs = array(); + if ($this->iswin32) { + $paths = split(';',$this->conf['TEST_PATHS']); + } else { + $paths = split(':|;',$this->conf['TEST_PATHS']); + } + foreach($paths as $path) { + $this->test_dirs[] = realpath($path); + } + } } - - function test_sort($a, $b) { - global $cwd; - $ta = strpos($a, "{$cwd}/tests")===0 ? 1 + (strpos($a, "{$cwd}/tests/run-test")===0 ? 1 : 0) : 0; - $tb = strpos($b, "{$cwd}/tests")===0 ? 1 + (strpos($b, "{$cwd}/tests/run-test")===0 ? 1 : 0) : 0; + function test_sort($a, $b) { + $ta = strpos($a, "{$this->cwd}/tests")===0 ? 1 + (strpos($a, "{$this->cwd}/tests/run-test")===0 ? 1 : 0) : 0; + $tb = strpos($b, "{$this->cwd}/tests")===0 ? 1 + (strpos($b, "{$this->cwd}/tests/run-test")===0 ? 1 : 0) : 0; if ($ta == $tb) { return strcmp($a, $b); } else { @@ -259,71 +743,26 @@ } } - function isExecutable() { - if (!$this->TEST_PHP_EXECUTABLE || - (function_exists('is_executable') && - !@is_executable($this->TEST_PHP_EXECUTABLE))) { - $this->error("invalid PHP executable specified by TEST_PHP_EXECUTABLE = " . - $this->TEST_PHP_EXECUTABLE); - return false; + function checkRequirements() { + if (version_compare(phpversion(), "5.0") < 0) { + $this->writemsg(REQ_PHP_VERSION); + exit; + } + if (!file_exists("/tmp")) { + $this->writemsg(TMP_MISSING); + exit; + } + if (!function_exists("proc_open")) { + $this->writemsg(PROC_OPEN_MISSING); + exit; } - return true; - } - - function checkPCRE() { if (!extension_loaded("pcre")) { - echo <<<NO_PCRE_ERROR - -+-----------------------------------------------------------+ -| ! ERROR ! | -| The test-suite requires that you have pcre extension | -| enabled. To enable this extension either compile your PHP | -| with --with-pcre-regex or if you have compiled pcre as a | -| shared module load it via php.ini. | -+-----------------------------------------------------------+ - -NO_PCRE_ERROR; - exit; + $this->writemsg(PCRE_MISSING_ERROR); + exit; } - } - - function checkSafeMode() { if (ini_get('safe_mode')) { - $safewarn = <<< SAFE_MODE_WARNING - -+-----------------------------------------------------------+ -| ! WARNING ! | -| You are running the test-suite with "safe_mode" ENABLED ! | -| | -| Chances are high that no test will work at all, | -| depending on how you configured "safe_mode" ! | -+-----------------------------------------------------------+ - - -SAFE_MODE_WARNING; - writemsg($safewarn); - return true; + $this->writemsg(SAFE_MODE_WARNING); } - return false; - } - - function getExecutableInfo() - { - $info_file = realpath(dirname(__FILE__)) . '/run-test-info.php'; - @unlink($info_file); - $php_info = '<?php echo " -PHP_SAPI : " . PHP_SAPI . " -PHP_VERSION : " . phpversion() . " -ZEND_VERSION: " . zend_version() . " -PHP_OS : " . PHP_OS . " -INI actual : " . realpath(get_cfg_var("cfg_file_path")) . " -More .INIs : " . (function_exists(\'php_ini_scanned_files\') ? str_replace("\n","", php_ini_scanned_files()) : "** not determined **"); ?>'; - $this->save_text($info_file, $php_info); - $this->settings2array($this->ini_overwrites,$this->info_params); - $this->settings2params($this->info_params); - $php_info = `{$this->TEST_PHP_EXECUTABLE} {$this->info_params} -f $info_file`; - @unlink($info_file); - return $php_info; } // @@ -331,34 +770,75 @@ // function contextHeader() { - $ini=''; - if (function_exists('php_ini_scanned_files')) { - $ini=php_ini_scanned_files(); + $info = ''; + foreach ($this->exec_info as $k=>$v) { + $info .= sprintf("%-20.s: %s\n",$k,$v); + } + $exts = ''; + foreach ($this->exts_to_test as $ext) { + $exts .="$ext\n "; } - - $info = $this->getExecutableInfo(); - - $this->writemsg("\n$this->ddash\n". - "CWD : {$this->cwd}\n". - "PHP : {$this->TEST_PHP_EXECUTABLE} $info\n". - "Test Dirs : "); + $dirs = ''; foreach ($this->test_dirs as $test_dir) { - $this->writemsg("$test_dir\n "); + $dirs .= "$test_dir\n "; } - $this->writemsg("\n$this->ddash\n"); + $conf = ''; + foreach ($this->conf as $k=>$v) { + $conf .= sprintf("%-20.s: %s\n",$k,$v); + } + + $exeinfo = ''; + if (!$this->conf['TEST_WEB']) + $exeinfo = "CWD : {$this->cwd}\n". + "PHP : {$this->conf['TEST_PHP_EXECUTABLE']}\n"; + + $this->writemsg("\n$this->ddash\n". + "$exeinfo$info\n". + "Test Harness Configuration:\n$conf\n". + "Extensions : $exts\n". + "Test Dirs : $dirs\n". + "$this->ddash\n"); } function loadFileList() { foreach ($this->test_dirs as $dir) { - print "searching {$this->cwd}/{$dir}\n"; - $this->findFilesInDir("{$this->cwd}/$dir", ($dir == 'ext')); - #$this->findFilesInDir($dir, ($dir == 'ext')); + if (is_dir($dir)) { + $this->findFilesInDir($dir, ($dir == 'ext')); + } else { + $this->test_files[] = $dir; + } } usort($this->test_files,array($this,"test_sort")); $this->writemsg("found ".count($this->test_files)." files\n"); } + function moveTestFiles() + { + if (!$this->conf['TEST_BASE_PATH'] || + $this->conf['TEST_BASE_PATH'] == $this->conf['TEST_PHP_SRCDIR']) return; + $this->writemsg("moving files from {$this->conf['TEST_PHP_SRCDIR']} to {$this->conf['TEST_BASE_PATH']}\n"); + $l = strlen($this->conf['TEST_PHP_SRCDIR']); + $files = array(); + $dirs = array(); + foreach ($this->test_files as $file) { + if (strpos($file,$this->conf['TEST_PHP_SRCDIR'])==0) { + $newlocation = $this->conf['TEST_BASE_PATH'].substr($file,$l); + $files[] = $newlocation; + $dirs[dirname($file)] = dirname($newlocation); + } else { + // XXX what to do with test files outside the + // php source directory? Need to map them into + // the new directory somehow. + } + } + foreach ($dirs as $src=>$new) { + mkpath($new); + copyfiles($src,$new); + } + $this->test_files = $files; + } + function findFilesInDir($dir,$is_ext_dir=FALSE,$ignore=FALSE) { $skip = array('.', '..', 'CVS'); @@ -402,14 +882,6 @@ } } - // Probably unnecessary for CLI, but used when overloading a - // web-based test class - - function runFooter() - { - - } - function run() { $this->start_time = time(); @@ -430,7 +902,6 @@ } } $this->end_time = time(); - $this->runFooter(); } function summarizeResults() @@ -479,12 +950,12 @@ $failed_test_summary .= $this->ddash."\n"; } - if ($failed_test_summary && !$this->NO_PHPTEST_SUMMARY) { + if ($failed_test_summary && !$this->conf['NO_PHPTEST_SUMMARY']) { $this->writemsg($failed_test_summary); } /* We got failed Tests, offer the user to send and e-mail to QA team, unless NO_INTERACTION is set */ - if ($sum_results['FAILED'] && !$this->NO_INTERACTION) { + if ($sum_results['FAILED'] && !$this->conf['NO_INTERACTION']) { $fp = fopen("php://stdin", "r+"); $this->writemsg("\nPlease allow this report to be send to the PHP QA\nteam. This will give us a better understanding in how\n"); $this->writemsg("PHP's test cases are doing.\n"); @@ -514,13 +985,12 @@ $sep = "\n" . str_repeat('=', 80) . "\n"; $failed_tests_data .= $failed_test_summary . "\n"; - $failed_tests_data .= $summary . "\n"; - if (sum($this->failed_tests)) { + if (array_sum($this->failed_tests)) { foreach ($this->failed_tests as $test_info) { $failed_tests_data .= $sep . $test_info['name']; - $failed_tests_data .= $sep . $this->getFileContents($test_info['output']); - $failed_tests_data .= $sep . $this->getFileContents($test_info['diff']); + $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output'])); + $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff'])); $failed_tests_data .= $sep . "\n\n"; } $status = "failed"; @@ -532,7 +1002,7 @@ $failed_tests_data .= "OS:\n". PHP_OS. "\n\n"; $automake = $autoconf = $libtool = $compiler = 'N/A'; - if (substr(PHP_OS, 0, 3) != "WIN") { + if (!$this->iswin32) { $automake = shell_exec('automake --version'); $autoconf = shell_exec('autoconf --version'); /* Always use the generated libtool - Mac OSX uses 'glibtool' */ @@ -541,9 +1011,9 @@ $flags = array('-v', '-V', '--version'); $cc_status=0; foreach($flags AS $flag) { - system(getenv('CC')." $flag >/dev/null 2>&1", $cc_status); + system($this->env['CC']." $flag >/dev/null 2>&1", $cc_status); if($cc_status == 0) { - $compiler = shell_exec(getenv('CC')." $flag 2>&1"); + $compiler = shell_exec($this->env['CC']." $flag 2>&1"); break; } } @@ -561,11 +1031,12 @@ } $failed_tests_data .= $sep . "PHPINFO" . $sep; - $failed_tests_data .= shell_exec($this->TEST_PHP_EXECUTABLE.' -dhtml_errors=0 -i'); + $failed_tests_data .= shell_exec($this->conf['TEST_PHP_EXECUTABLE'].' -dhtml_errors=0 -i'); $compression = 0; - if ($just_save_results || !$this->mail_qa_team($failed_tests_data, $compression, $status)) { + if ($just_save_results || + !post_result_data("status=$status&version=".urlencode(TESTED_PHP_VERSION),$failed_tests_data)) { $output_file = 'php_test_results_' . date('Ymd_Hi') . ( $compression ? '.txt.gz' : '.txt' ); $fp = fopen($output_file, "w"); fwrite($fp, $failed_tests_data); @@ -581,62 +1052,88 @@ } } - if($this->REPORT_EXIT_STATUS == 1 and $sum_results['FAILED']) { + if($this->conf['REPORT_EXIT_STATUS'] and $sum_results['FAILED']) { exit(1); } } - function getFileContents($filename) + function getINISettings(&$section_text) { - $real_filename = realpath($filename); - if (function_exists('file_get_contents')) { - return file_get_contents($real_filename); - } - - $fd = fopen($real_filename, "rb"); - if ($fd) { - $contents = fread($fd, filesize($real_filename)); - fclose($fd); - return $contents; + $ini_settings = $this->ini_overwrites; + // Any special ini settings + // these may overwrite the test defaults... + if (array_key_exists('INI', $section_text)) { + settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings); } - return NULL; + return $ini_settings; } - function settings2array($settings, &$ini_settings) + function getINIParams(&$section_text) { - foreach($settings as $setting) { - if (strpos($setting, '=')!==false) { - $setting = explode("=", $setting, 2); - $name = trim(strtolower($setting[0])); - $value = trim($setting[1]); - $ini_settings[$name] = $value; - } + if (!$section_text) return ''; + // XXX php5 current has a problem doing this in one line + // it fails with Only variables can be passed by reference + // on test ext\calendar\tests\jdtojewish.phpt + // return settings2params($this->getINISettings($section_text)); + $ini = $this->getINISettings($section_text); + return settings2params($ini); + } + + function calculateDocumentRoot() + { + if ($this->conf['TEST_WEB'] || $this->test_executable_iscgi) { + // configure DOCUMENT_ROOT for web tests + // this assumes that directories from the base url + // matches directory depth from the base path + $parts = parse_url($this->conf['TEST_WEB_BASE_URL']); + $depth = substr_count($parts['path'],'/'); + $docroot = $this->conf['TEST_BASE_PATH']; + for ($i=0 ; $i < $depth; $i++) $docroot = dirname($docroot); + $this->conf['TEST_DOCUMENT_ROOT']=$docroot; + $this->conf['TEST_BASE_SCRIPT_NAME']=$parts['path']; + $this->conf['TEST_SERVER_URL']=substr($this->conf['TEST_WEB_BASE_URL'],0,strlen($this->conf['TEST_WEB_BASE_URL'])-strlen($parts['path'])); + } else { + $this->conf['TEST_DOCUMENT_ROOT']=''; + $this->conf['TEST_BASE_SCRIPT_NAME']=''; + $this->conf['TEST_SERVER_URL']=''; } } - function settings2params(&$ini_settings) + function evalSettings($filename,$data) { + // we eval the section so we can allow dynamic env vars + // for cgi testing + $filename = str_replace('\\','/',$filename); + $cwd = str_replace('\\','/',$this->cwd); + $filepath = dirname($filename); + $scriptname = substr($filename,strlen($this->conf['TEST_DOCUMENT_ROOT'])); + // eval fails if no newline + return eval("$data\n"); + } + + function getENVSettings(&$section_text,$testfile) { - if (count($ini_settings)) { - $settings = ''; - foreach($ini_settings as $name => $value) { - $value = addslashes($value); - $settings .= " -d \"$name=$value\""; - } - $ini_settings = $settings; - } else { - $ini_settings = ''; + $env = $this->env; + // Any special environment settings + // these may overwrite the test defaults... + if (array_key_exists('ENV', $section_text)) { + $sect = $this->evalSettings($testfile,$section_text['ENV']); + //print "data evaled:\n$sect\n"; + settings2array(preg_split( "/[\n\r]+/", $sect), $env); } + return $env; } - function getINISettings(&$section_text) + function getEvalTestSettings($section_text,$testfile) { - $ini_settings = $this->ini_overwrites; - // Any special ini settings + $rq = array(); + // Any special environment settings // these may overwrite the test defaults... - if (array_key_exists('INI', $section_text)) { - $this->settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings); + if ($section_text) { + $sect = $this->evalSettings($testfile,$section_text); + //print "data evaled:\n$sect\n"; + settings2array(preg_split( "/[\n\r]+/", $sect), $rq); } - return $this->settings2params($ini_settings); + return $rq; } // @@ -660,7 +1157,6 @@ $section = ''; while (!feof($fp)) { $line = fgets($fp); - // Match the beginning of a section. if (ereg('^--([A-Z]+)--',$line,$r)) { $section = $r[1]; @@ -672,83 +1168,69 @@ $section_text[$section] .= $line; } fclose($fp); - return $section_text; - } - - function setEnvironment($env) - { - foreach ($env as $name=>$value) { - putenv("$name=$value"); + foreach ($section_text as $k=>$v) { + // for POST data ,we only want to trim the last new line! + if ($k == 'POST' && preg_match('/^(.*?)\r?\n$/Ds',$v,$matches)) { + $section_text[$k]=$matches[1]; + } else { + $section_text[$k]=trim($v); + } } + return $section_text; } - + // // Check if test should be skipped. // - function getSkipReason(&$section_text) + function getSkipReason($file,&$section_text,$docgi=false) { - if (array_key_exists('SKIPIF', $section_text)) { - $tmp_skipif = $section_text['_DIR'] . uniqid('/phpt.'); - @unlink($tmp_skipif); - if (trim($section_text['SKIPIF'])) { - $this->save_text($tmp_skipif, $section_text['SKIPIF']); - $output = `{$this->TEST_PHP_EXECUTABLE} {$this->info_params} $tmp_skipif`; - @unlink($tmp_skipif); - if (eregi("^skip", trim($output))){ - - $reason = (ereg("^skip[[:space:]]*(.+)\$", trim($output))) ? ereg_replace("^skip[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE; - $this->showstatus($section_text['TEST'], 'SKIPPED', $reason); - - return 'SKIPPED'; + // if the test uses POST or GET, and it's not the cgi + // executable, skip + if ($docgi && !$this->conf['TEST_WEB'] && !$this->test_executable_iscgi) { + $this->showstatus($section_text['TEST'], 'SKIPPED', 'CGI Test needs CGI Binary'); + return "SKIPPED"; + } + // if we're doing web testing, then we wont be able to set + // ini setting on the command line. be sure the executables + // ini settings are compatible with the test, or skip + if (($docgi || $this->conf['TEST_WEB']) && + isset($section_text['INI']) && $section_text['INI']) { + $settings = $this->getINISettings($section_text); + foreach ($settings as $k=>$v) { + if (strcasecmp($v,'off')==0 || !$v) $v=''; + $haveval = isset($this->inisettings[$k]['local_value']); + if ($k == 'include_path') { + // we only want to know that src directory + // is in the include path + if (strpos($this->inisettings[$k]['local_value'],$this->cwd)) + continue; } - if (eregi("^info", trim($output))) { - $reason = (ereg("^info[[:space:]]*(.+)\$", trim($output))) ? ereg_replace("^info[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE; - if ($reason) { - $tested .= " (info: $reason)"; - } + if (($haveval && $this->inisettings[$k]['local_value'] != $v) || (!$haveval && $v)) { + $this->showstatus($section_text['TEST'], 'SKIPPED', "Test requires ini setting $k=[$v], not [".($haveval?$this->inisettings[$k]['local_value']:'')."]"); + return "SKIPPED"; } } } - return NULL; - } - - function execute($commandline) - { - $data = ""; - - $proc = proc_open($commandline, array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w') - ), $pipes); - - if (!$proc) - return false; - fclose($pipes[0]); - - while (true) { - /* hide errors from interrupted syscalls */ - $r = $pipes; - $w = null; - $e = null; - $n = @stream_select($r, $w, $e, 60); - - if ($n == 0) { - /* timed out */ - $data .= "\n ** ERROR: process timed out **\n"; - proc_terminate($proc); - return $data; - } else if ($n) { - $line = fread($pipes[1], 8192); - if (strlen($line) == 0) { - /* EOF */ - break; + // now handle a SKIPIF section + if ($section_text['SKIPIF']) { + $output = trim($this->runscript($section_text['SKIPIF'],$this->test_executable_iscgi,realpath(dirname($file))),true); + if (!$output) return NULL; + if ($this->conf['TEST_PHP_DETAILED'] > 2) + print "SKIPIF: [$output]\n"; + if (eregi("^skip", $output)){ + + $reason = (ereg("^skip[[:space:]]*(.+)\$", $output)) ? ereg_replace("^skip[[:space:]]*(.+)\$", "\\1", $output) : FALSE; + $this->showstatus($section_text['TEST'], 'SKIPPED', $reason); + return 'SKIPPED'; + } + if (eregi("^info", $output)) { + $reason = (ereg("^info[[:space:]]*(.+)\$", $output)) ? ereg_replace("^info[[:space:]]*(.+)\$", "\\1", $output) : FALSE; + if ($reason) { + $tested .= " (info: $reason)"; } - $data .= $line; } } - $code = proc_close($proc); - return $data; + return NULL; } // @@ -756,19 +1238,25 @@ // function run_test($file) { - if ($this->TEST_PHP_DETAILED) + if ($this->conf['TEST_PHP_DETAILED']) $this->writemsg("\n=================\nTEST $file\n"); $section_text = $this->getSectionText($file); - $shortname = str_replace($this->cwd.'/', '', $file); - $tested = trim($section_text['TEST'])." [$shortname]"; - - $tmp_file = ereg_replace('\.phpt$','.php',$file); - $tmp_post = $section_text['_DIR'] . uniqid('/phpt.'); - + if ($this->iswin32) + $shortname = str_replace($this->conf['TEST_BASE_PATH'].'\\', '', $file); + else + $shortname = str_replace($this->conf['TEST_BASE_PATH'].'/', '', $file); + $tested = $section_text['TEST']." [$shortname]"; + + if ($this->conf['TEST_WEB']) { + $tmp_file = ereg_replace('\.phpt$','.'.$this->conf['TEST_WEB_EXT'],$file); + $uri = $this->conf['TEST_BASE_SCRIPT_NAME'].str_replace($this->conf['TEST_BASE_PATH'], '', $tmp_file); + $uri = str_replace('\\', '/', $uri); + } else { + $tmp_file = ereg_replace('\.phpt$','.php',$file); + } @unlink($tmp_file); - @unlink($tmp_post); // unlink old test results @unlink(ereg_replace('\.phpt$','.diff',$file)); @@ -776,76 +1264,169 @@ @unlink(ereg_replace('\.phpt$','.exp',$file)); @unlink(ereg_replace('\.phpt$','.out',$file)); - // Reset environment from any previous test. - $env = $this->env; - $this->setEnvironment($env); + if (!$this->conf['TEST_WEB']) { + // Reset environment from any previous test. + $env = $this->getENVSettings($section_text,$tmp_file); + $ini_overwrites = $this->getINIParams($section_text); + } + + // if this is a cgi test, prepare for it + $query_string = ''; + $havepost = array_key_exists('POST', $section_text) && !empty($section_text['POST']); + // allow empty query_string requests + $haveget = array_key_exists('GET', $section_text) && !empty($section_text['GET']); + $do_cgi = array_key_exists('CGI', $section_text) || $haveget || $havepost; + + $skipreason = $this->getSkipReason($file,$section_text,$do_cgi); + if ($skipreason == 'SKIPPED') { + return $skipreason; + } - $skipreason = $this->getSkipReason($section_text); - if ($skipreason == 'SKIPPED') return $skipreason; - - $ini_overwrites = $this->getINISettings($section_text); - // We've satisfied the preconditions - run the test! - $this->save_text($tmp_file,$section_text['FILE']); - if (array_key_exists('GET', $section_text)) { - $query_string = trim($section_text['GET']); + save_to_file($tmp_file,$section_text['FILE']); + + $post = NULL; + $args = ""; + + $headers = array(); + if ($this->conf['TEST_WEB']) { + $request = $this->getEvalTestSettings(@$section_text['REQUEST'],$tmp_file); + $headers = $this->getEvalTestSettings(@$section_text['HEADERS'],$tmp_file); + + $method = isset($request['method'])?$request['method']:$havepost?'POST':'GET'; + $query_string = $haveget?$section_text['GET']:''; + + $options = array(); + $options['method']=$method; + if (isset($this->conf['timeout'])) $options['timeout'] = $this->conf['timeout']; + if (isset($this->conf['proxy_host'])) $options['proxy_host'] = $this->conf['proxy_host']; + if (isset($this->conf['proxy_port'])) $options['proxy_port'] = $this->conf['proxy_port']; + if (isset($this->conf['proxy_user'])) $options['proxy_user'] = $this->conf['proxy_user']; + if (isset($this->conf['proxy_pass'])) $options['proxy_pass'] = $this->conf['proxy_pass']; + + $post = $havepost?$section_text['POST']:NULL; + $url = $this->conf['TEST_SERVER_URL']; + if (isset($request['SCRIPT_NAME'])) + $url .= $request['SCRIPT_NAME']; + else + $url .= $uri; + if (isset($request['PATH_INFO'])) + $url .= $request['PATH_INFO']; + if (isset($request['FRAGMENT'])) + $url .= '#'.$request['FRAGMENT']; + if (isset($request['QUERY_STRING'])) + $query_string = $request['QUERY_STRING']; + if ($query_string) + $url .= '?'.$query_string; + if ($this->conf['TEST_PHP_DETAILED']) + $this->writemsg("\nURL = $url\n"); + } else if ($do_cgi) { + $query_string = $haveget?$section_text['GET']:''; + + if (!array_key_exists('GATEWAY_INTERFACE', $env)) + $env['GATEWAY_INTERFACE']='CGI/1.1'; + if (!array_key_exists('SERVER_SOFTWARE', $env)) + $env['SERVER_SOFTWARE']='PHP Test Harness'; + if (!array_key_exists('SERVER_SOFTWARE', $env)) + $env['SERVER_NAME']='127.0.0.1'; + if (!array_key_exists('REDIRECT_STATUS', $env)) + $env['REDIRECT_STATUS']='200'; + if (!array_key_exists('SERVER_NAME', $env)) + $env['QUERY_STRING']=$query_string; + if (!array_key_exists('PATH_TRANSLATED', $env) && + !array_key_exists('SCRIPT_FILENAME', $env)) { + $env['PATH_TRANSLATED']=$tmp_file; + $env['SCRIPT_FILENAME']=$tmp_file; + } + if (!array_key_exists('PATH_TRANSLATED', $env)) + $env['PATH_TRANSLATED']=''; + if (!array_key_exists('PATH_INFO', $env)) + $env['PATH_INFO']=''; + if (!array_key_exists('SCRIPT_NAME', $env)) + $env['SCRIPT_NAME']=''; + if (!array_key_exists('SCRIPT_FILENAME', $env)) + $env['SCRIPT_FILENAME']=''; + + if (array_key_exists('POST', $section_text) && (!$haveget || !empty($section_text['POST']))) { + $post = $section_text['POST']; + $content_length = strlen($post); + if (!array_key_exists('REQUEST_METHOD', $env)) + $env['REQUEST_METHOD']='POST'; + if (!array_key_exists('CONTENT_TYPE', $env)) + $env['CONTENT_TYPE']='application/x-www-form-urlencoded'; + if (!array_key_exists('CONTENT_LENGTH', $env)) + $env['CONTENT_LENGTH']=$content_length; + } else { + if (!array_key_exists('REQUEST_METHOD', $env)) + $env['REQUEST_METHOD']='GET'; + if (!array_key_exists('CONTENT_TYPE', $env)) + $env['CONTENT_TYPE']=''; + if (!array_key_exists('CONTENT_LENGTH', $env)) + $env['CONTENT_LENGTH']=''; + } + if ($this->conf['TEST_PHP_DETAILED'] > 1) + $this->writemsg("\nCONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . + "\nCONTENT_TYPE = " . $env['CONTENT_TYPE'] . + "\nPATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . + "\nPATH_INFO = " . $env['PATH_INFO'] . + "\nQUERY_STRING = " . $env['QUERY_STRING'] . + "\nREDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . + "\nREQUEST_METHOD = " . $env['REQUEST_METHOD'] . + "\nSCRIPT_NAME = " . $env['SCRIPT_NAME'] . + "\nSCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . "\n"); + /* not cgi spec to put query string on command line, + but used by a couple tests to catch a security hole + in older php versions. At least IIS can be configured + to do this. */ + $args = $env['QUERY_STRING']; } else { - $query_string = ''; + $args = $section_text['ARGS'] ? $section_text['ARGS'] : ''; + $args = "$ini_overwrites $tmp_file $args 2>&1"; } - - $env['REDIRECT_STATUS']='1'; - $env['QUERY_STRING']=$query_string; - $env['PATH_TRANSLATED']=$tmp_file; - $env['SCRIPT_FILENAME']=$tmp_file; - - $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : ''; - - if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { - - $post = trim($section_text['POST']); - $this->save_text($tmp_post,$post); - $content_length = strlen($post); - - $env['REQUEST_METHOD']='POST'; - $env['CONTENT_TYPE']='application/x-www-form-urlencoded'; - $env['CONTENT_LENGTH']=$content_length; - - $cmd = "{$this->TEST_PHP_EXECUTABLE} $ini_overwrites -f $tmp_file 2>&1 < $tmp_post"; - + + if ($this->conf['TEST_WEB']) { + // we want headers also, so fopen + $r = new HTTPRequest($url,$headers,$options,$post); + //$out = preg_replace("/\r\n/","\n",$r->response); + $out = $r->response; + $headers = $r->response_headers; + //print $r->outgoing_payload."\n"; + //print $r->incoming_payload."\n"; } else { - - $env['REQUEST_METHOD']='GET'; - $env['CONTENT_TYPE']=''; - $env['CONTENT_LENGTH']=''; - - $cmd = "{$this->TEST_PHP_EXECUTABLE} $ini_overwrites -f $tmp_file$args 2>&1"; + $out = execute($this->conf['TEST_PHP_EXECUTABLE'],$args,$post,$this->cwd,$env); + // if this is a cgi, remove the headers first + if ($this->test_executable_iscgi + && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) { + $out = $match[2]; + $rh = preg_split("/[\n\r]+/",$match[1]); + $headers = array(); + foreach ($rh as $line) { + if (strpos($line, ':')!==false) { + $line = explode(":", $line, 2); + $headers[trim($line[0])] = trim($line[1]); + } + } + } } - - if ($this->TEST_PHP_DETAILED) - $this->writemsg("\nCONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . - "\nCONTENT_TYPE = " . $env['CONTENT_TYPE'] . - "\nPATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . - "\nQUERY_STRING = " . $env['QUERY_STRING'] . - "\nREDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . - "\nREQUEST_METHOD = " . $env['REQUEST_METHOD'] . - "\nSCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . - "\nCOMMAND $cmd\n"); - - $this->setEnvironment($env); - $out = $this->execute($cmd); - - @unlink($tmp_post); - + if ($this->conf['TEST_PHP_DETAILED'] > 2) { + echo "HEADERS: "; + print_r($headers); + echo "OUTPUT: \n$out\n"; + + } + // Does the output match what is expected? $output = trim($out); $output = preg_replace('/\r\n/',"\n",$output); - + + $failed = FALSE; + if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { if (isset($section_text['EXPECTF'])) { - $wanted = trim($section_text['EXPECTF']); + $wanted = $section_text['EXPECTF']; } else { - $wanted = trim($section_text['EXPECTREGEX']); + $wanted = $section_text['EXPECTREGEX']; } $wanted_re = preg_replace('/\r\n/',"\n",$wanted); if (isset($section_text['EXPECTF'])) { @@ -860,28 +1441,53 @@ // %f allows two points "-.0.0" but that is the best *simple* expression } /* DEBUG YOUR REGEX HERE - var_dump($wanted); + var_dump($wanted_re); print(str_repeat('=', 80) . "\n"); var_dump($output); */ - if (preg_match("/^$wanted_re\$/s", $output)) { - @unlink($tmp_file); - $this->showstatus($tested, 'PASSED'); - return 'PASSED'; + $failed = !preg_match("/^$wanted_re\$/s", $output); + } + + $skipexpect = false; + if (!$failed && $this->conf['TEST_WEB'] && isset($section_text['EXPECTHEADERS'])) { + $want = array(); + $lines = preg_split("/[\n\r]+/",$section_text['EXPECTHEADERS']); + $wanted=''; + foreach ($lines as $line) { + if (strpos($line, ':')!==false) { + $line = explode(":", $line, 2); + $want[trim($line[0])] = trim($line[1]); + $wanted .= trim($line[0]).': '.trim($line[1])."\n"; + } + } + $output=''; + foreach ($want as $k=>$v) { + $output .= "$k: {$headers[$k]}\n"; + if (!isset($headers[$k]) || $headers[$k] != $v) { + $failed = TRUE; + } } - - } else { - $wanted = trim($section_text['EXPECT']); + + // different servers may do different things on non-200 results + // for instance, IIS will deliver it's own error pages, so we + // cannot expect to match up the EXPECT section. We may however, + // want to match EXPECT on more than 200 results, so this may + // need to change later. + $skipexpect = isset($headers['Status']) && $headers['Status'] != 200; + } + + if (!$failed && !$skipexpect && isset($section_text['EXPECT'])) { + $wanted = $section_text['EXPECT']; $wanted = preg_replace('/\r\n/',"\n",$wanted); - // compare and leave on success - $ok = (0 == strcmp($output,$wanted)); - if ($ok) { - @unlink($tmp_file); - $this->showstatus($tested, 'PASSED'); - return 'PASSED'; - } + $failed = (0 != strcmp($output,$wanted)); } - + + if (!$failed) { + @unlink($tmp_file); + $this->showstatus($tested, 'PASSED'); + return 'PASSED'; + } + // Test failed so we need to report details. $this->showstatus($tested, 'FAILED'); @@ -892,88 +1498,50 @@ 'diff' => ereg_replace('\.phpt$','.diff', $file) ); + if ($this->conf['TEST_PHP_DETAILED']) + $this->writemsg(generate_diff($wanted,$output)."\n"); + // write .exp - if (strpos($this->TEST_PHP_LOG_FORMAT,'E') !== FALSE) { + if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'E') !== FALSE) { $logname = ereg_replace('\.phpt$','.exp',$file); - $this->save_text($logname,$wanted); + save_to_file($logname,$wanted); } // write .out - if (strpos($this->TEST_PHP_LOG_FORMAT,'O') !== FALSE) { + if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'O') !== FALSE) { $logname = ereg_replace('\.phpt$','.out',$file); - $this->save_text($logname,$output); + save_to_file($logname,$output); } // write .diff - if (strpos($this->TEST_PHP_LOG_FORMAT,'D') !== FALSE) { + if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'D') !== FALSE) { $logname = ereg_replace('\.phpt$','.diff',$file); - $this->save_text($logname,$this->generate_diff($wanted,$output)); + save_to_file($logname,generate_diff($wanted,$output)); } // write .log - if (strpos($this->TEST_PHP_LOG_FORMAT,'L') !== FALSE) { + if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'L') !== FALSE) { $logname = ereg_replace('\.phpt$','.log',$file); - $this->save_text($logname, + save_to_file($logname, "\n---- EXPECTED OUTPUT\n$wanted\n". "---- ACTUAL OUTPUT\n$output\n". "---- FAILED\n"); - $this->error_report($file,$logname,$tested); + // display emacs/msvc error output + if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'C') !== FALSE) { + $this->error_report($file,$logname,$tested); + } } - return 'FAILED'; } // - // Send Email to QA Team - // - function mail_qa_team($data, $compression) - { - $url_bits = parse_url(QA_SUBMISSION_PAGE); - if (empty($url_bits['port'])) $url_bits['port'] = 80; - - $data = "php_test_data=" . urlencode(base64_encode(preg_replace("/[\\x00]/", "[0x0]", $data))); - $data_length = strlen($data); - - $fs = fsockopen($url_bits['host'], $url_bits['port'], $errno, $errstr, 10); - if (!$fs) { - return FALSE; - } - - $this->writemsg("Posting to {$url_bits['host']} {$url_bits['path']}\n"); - fwrite($fs, "POST ".$url_bits['path']." HTTP/1.1\r\n"); - fwrite($fs, "Host: ".$url_bits['host']."\r\n"); - fwrite($fs, "User-Agent: QA Browser 0.1\r\n"); - fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n"); - fwrite($fs, "Content-Length: ".$data_length."\r\n\r\n"); - fwrite($fs, $data); - fwrite($fs, "\r\n\r\n"); - fclose($fs); - - return TRUE; - } - - // - // Write the given text to a temporary file, and return the filename. - // - function save_text($filename,$text) - { - $fp = @fopen($filename,'w') - or $this->error("Cannot open file '" . $filename . "' (save_text)"); - fwrite($fp,$text); - fclose($fp); - if (1 < $this->TEST_PHP_DETAILED) { - $this->writemsg("\nFILE $filename {{{\n$text\n}}}\n"); - } - } - - // // Write an error in a format recognizable to Emacs or MSVC. // function error_report($testname,$logname,$tested) { $testname = realpath($testname); $logname = realpath($logname); - switch ($this->TEST_PHP_ERROR_STYLE) { + switch ($this->conf['TEST_PHP_ERROR_STYLE']) { default: case 'MSVC': $this->writemsg($testname . "(1) : $tested\n"); @@ -986,152 +1554,10 @@ } } - function generate_diff($wanted,$output) - { - $w = explode("\n", $wanted); - $o = explode("\n", $output); - $w1 = array_diff_assoc($w,$o); - $o1 = array_diff_assoc($o,$w); - $w2 = array(); - $o2 = array(); - foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1).$val; - foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1).$val; - $diff = array_merge($w2, $o2); - ksort($diff); - return implode("\r\n", $diff); - } - - function error($message) - { - $this->writemsg("ERROR: {$message}\n"); - exit(1); - } -} - -class webHarness extends testHarness { - - var $textdata; - - function checkSafeMode() { - if (ini_get('safe_mode')) { - -?> -<CENTER> -<TABLE CELLPADDING=5 CELLSPACING=0 BORDER=1> -<TR> -<TD BGCOLOR="#FE8C97" ALIGN=CENTER><B>WARNING</B> -<HR NOSHADE COLOR=#000000> -You are running this test-suite with "safe_mode" <B>ENABLED</B>!<BR><BR> -Chances are high that none of the tests will work at all, depending on -how you configured "safe_mode". -</TD> -</TR> -</TABLE> -</CENTER> -<?php - return true; - } - return false; - } - - function runHeader() { -?> -<TABLE CELLPADDING=3 CELLSPACING=0 BORDER=0 STYLE="border: thin solid black;"> -<TR> - <TD>TESTED FUNCTIONALITY</TD> - <TD>RESULT</TD> -</TR> -<?php - - } - - function runFooter() { - - -?> -<TR> -<TD COLSPAN=2 ALIGN=CENTER><FONT SIZE=3>Additional Notes</FONT><HR><?php $this->displaymsg(); ?></TD> -</TR> -</TABLE><BR><BR> -<?php - } - function error($message) { $this->writemsg("ERROR: {$message}\n"); exit(1); - } - - // Use this function to do any displaying of text, so that - // things can be over-written as necessary. - - function writemsg($msg) { - - $this->textdata = $this->textdata . $msg; - - } - - function displaymsg() { - -?> -<TEXTAREA ROWS=10 COLS=80><?=$this->textdata?></TEXTAREA> -<?php - } - - // Another wrapper function, this one should be used any time - // a particular test passes or fails - - function showstatus($item, $status, $reason = '') - { - static $color = "#FAE998"; - - $color = ($color == "#FAE998") ? "#FFFFFF" : "#FAE998"; - - switch($status) { - - case 'PASSED': - -?> -<TR> -<TD BGCOLOR=<?=$color?>><?=$item?></TD> -<TD VALIGN=CENTER ALIGN=CENTER BGCOLOR=<?=$color?> ROWSPAN=2><FONT COLOR=#00FF00>PASSED</FONT></TD> -</TR> -<TR> -<TD BGCOLOR=<?=$color?>>Notes: <?=htmlentities($reason)?></TD> -</TR> -<?php - - break; - - case 'FAILED': - -?> -<TR> -<TD BGCOLOR=<?=$color?>><?=$item?></TD> -<TD VALIGN=CENTER ALIGN=CENTER BGCOLOR=<?=$color?> ROWSPAN=2><FONT COLOR=#FF0000>FAILED</FONT></TD> -</TR> -<TR> -<TD BGCOLOR=<?=$color?>>Notes: <?=htmlentities($reason)?></TD> -</TR> -<?php - - break; - - case 'SKIPPED': - -?> -<TR> -<TD BGCOLOR=<?=$color?>><?=$item?></TD> -<TD VALIGN=CENTER ALIGN=CENTER BGCOLOR=<?=$color?> ROWSPAN=2><FONT COLOR=#000000>SKIPPED</FONT></TD> -</TR> -<TR> -<TD BGCOLOR=<?=$color?>>Notes: <?=htmlentities($reason)?></TD> -</TR> -<?php - break; - - } - } } Index: php4/README.TESTING2 +++ php4/README.TESTING2 [IMPORTANT NOTICE] ------------------ This is an addendum to README.TESTING with additional information specific to run-tests2.php. run-tests2.php is backward compatible with tests developed for the original run-tests.php script. run-tests2 is *not* used by 'make test'. run-tests2 was developed to provide support for testing PHP under it's primary environment, HTTP, and can run the PHP tests under any of the SAPI modules that are direct executables, or are accessable via HTTP. [New features] ---------------- * Command line interface: You can run 'php run-tests2.php -h' to get all the possible options. * Configuration file: the -c argument will allow you to use a configuration file. This is handy if you are testing multiple environments and need various options depending on the environment. see run-tests-config.php for details. * CGI Emulation: Will emulate a CGI environment when testing with the cgi sapi executable. * HTTP testing: can be configured to run test scripts through an HTTP server running on localhost. localhost is required since either the web server must alias a directory to the php source directory, or the test scripts must be copied to a directory under the web server (see config options TEST_WEB_BASE_URL, TEST_BASE_PATH, and TEST_WEB_EXT) * New sections supported for test files (see below) When running tests over http, tests that require ini settings different that what the web server runs under will be skipped. Since the test harness defines a number of ini settings by default, the web server may require special configuration to make testing work. [Example Usage] ---------------- Some (but not all!) examples of usage: 1. run tests from the php source directory php run-tests2.php -p /path/to/php-cli 2. run tests using cgi emulation php run-tests2.php -p /path/to/php-cgi 3. run tests over http, copying test files into document root php run-tests2.php -w -u http://localhost/test -m /path/to/htdocs/test 4. run tests over http, php sources have been aliased in web server php run-tests2.php -w -u http://localhost/test 5. run tests using configuration file php run-tests2.php -c /path/to/run-tests-config.php 6. run tests using configuration file, but overriding some settings: (config file must be first) php run-tests2.php -c /path/to/run-tests-config.php -w -t 3 -d /path/to/testdir NOTE: configuration as described in README.TESTING still works. [New Test Sections] ---------------- In addition to the traditional test sections (see http://qa.php.net/write-test.php), several new sections are available under run-tests2. --POST-- This is not a new section, but not multipart posts are supported for testing file uploads, or other types of POST data. --CGI-- This section takes no value. It merely provides a simple marker for tests that MUST be run as CGI, even if there is no --POST-- or --GET-- sections in the test file. --DESCRIPTION-- Not used for anything, just a section for documenting the test --ENV-- This section get's eval()'d to help build an environment for the execution of the test. This can be used to change environment vars that are used for CGI emulation, or simply to set env vars for cli testing. A full example looks like: --ENV-- return <<<END PATH_TRANSLATED=$filename PATH_INFO=$scriptname SCRIPT_NAME=$scriptname END; Some variables are made easily available for use in this section, they include: $filename full native path to file, will become PATH_TRANSLATED $filepath =dirname($filename) $scriptname this is what will become SCRIPT_NAME unless you override it $docroot the equivelant of DOCUMENT_ROOT under Apache $cwd the directory that the test is being initiated from $this->conf all run-tests2 configuration vars $this->env all environment variables that will get passed to the test --REQUEST-- This section is also eval'd, and is similar in nature to --ENV--. However, this section is used to build the url used in an HTTP request. Valid values to set in this section would include: SCRIPT_NAME The inital part of the request url PATH_INFO The pathinfo part of a request url FRAGMENT The fragment section of a url (after #) QUERY_STRING The query part of a url (after ?) --REQUEST-- return <<<END PATH_INFO=/path/info END; --HEADERS-- This section is also eval'd. It is used to provide additional headers sent in an HTTP request, such as content type for multipart posts, cookies, etc. --HEADERS-- return <<<END Content-Type=multipart/form-data; boundary=---------------------------240723202011929 Content-Length=100 END; --EXPECTHEADERS-- This section can be used to define what headers are required to be received back from a request, and is checked in addition to the regular expect sections. For example: --EXPECTHEADERS-- Status: 404 Index: php4/run-tests-config.php +++ php4/run-tests-config.php <?php /* this file may be duplicated to provide testing for multiple php binaries or configurations. It is used with the -c option on run_tests2.php. All these settings will also go into the environment for tests that are directly executed, so you can also set things like PHPRC here to force an executable to use a specific php.ini file. */ $conf = array( /* path to the php source tree */ 'TEST_PHP_SRCDIR' => NULL, /* executable that will be tested. Not used for web based tests */ 'TEST_PHP_EXECUTABLE' => NULL, /* php.ini to use when executing php */ 'PHPRC' => NULL, /* log format */ 'TEST_PHP_LOG_FORMAT' => 'LEODC', /* debugging detail in output. */ 'TEST_PHP_DETAILED' => 0, /* error style for editors or IDE's */ 'TEST_PHP_ERROR_STYLE' => 'EMACS', 'REPORT_EXIT_STATUS' => 0, 'NO_PHPTEST_SUMMARY' => 0, /* don't ask, and don't send results to QA if true */ 'NO_INTERACTION' => true, /* base url prefixed to any requests */ 'TEST_WEB_BASE_URL' => NULL, /* if set, copy phpt files into this directory, which should be accessable via an http server. The TEST_WEB_BASE_URL setting should be the base url to access this path. If this is not used, TEST_WEB_BASE_URL should be the base url pointing to TEST_PHP_SRCDIR, which should then be accessable via an http server. An example would be: TEST_WEB_BASE_URL=http://localhost/test TEST_BASE_PATH=/path/to/htdocs/test */ 'TEST_BASE_PATH' => NULL, /* file extension of pages requested via http this allows for php to be configured to parse extensions other than php, usefull for multiple configurations under a single webserver */ 'TEST_WEB_EXT' => 'php', /* if true doesn't run tests, just outputs executable info */ 'TEST_CONTEXT_INFO' => false, /* : or ; seperated list of paths */ 'TEST_PATHS' => NULL /* additional configuration items that may be set to provide proxy support for testes: timeout proxy_host proxy_port proxy_user proxy_pass */ ); ?> Index: php4/sapi/tests/test001.phpt +++ php4/sapi/tests/test001.phpt --TEST-- IIS style CGI missing SCRIPT_FILENAME --DESCRIPTION-- This would be similar to what IIS produces for a simple query. --ENV-- return <<<END PATH_TRANSLATED=$filename PATH_INFO=$scriptname SCRIPT_NAME=$scriptname END; --CGI-- --FILE-- <?php echo "HELLO"; ?> --EXPECT-- HELLO Index: php4/sapi/tests/test002.phpt +++ php4/sapi/tests/test002.phpt --TEST-- Apache style CGI --DESCRIPTION-- Apache likes to set SCRIPT_FILENAME to the php executable if you use ScriptAlias configurations, and the proper path is in PATH_TRANSLATED. SCRIPT_NAME in this is faked, but that is ok, Apache sets SCRIPT_NAME to the ScriptAlias of the executable. --ENV-- return <<<END REDIRECT_URL=$scriptname PATH_TRANSLATED=$filename PATH_INFO=$scriptname SCRIPT_NAME=/scriptalias/php SCRIPT_FILENAME=$this->conf['TEST_PHP_EXECUTABLE'] END; --CGI-- --FILE-- <?php echo "HELLO"; ?> --EXPECT-- HELLO Index: php4/sapi/tests/test003.phpt +++ php4/sapi/tests/test003.phpt --TEST-- IIS style CGI missing SCRIPT_FILENAME, has PATH_INFO --DESCRIPTION-- This would be similar to what IIS produces for a simple query that also has PATH_INFO. --REQUEST-- return <<<END PATH_INFO=/path/info END; --ENV-- return <<<END PATH_TRANSLATED=$filename/path/info PATH_INFO=$scriptname/path/info SCRIPT_NAME=$scriptname END; --CGI-- --FILE-- <?php echo $_SERVER['PATH_INFO']; ?> --EXPECT-- /path/info Index: php4/sapi/tests/test004.phpt +++ php4/sapi/tests/test004.phpt --TEST-- Apache style CGI with PATH_INFO --DESCRIPTION-- Apache likes to set SCRIPT_FILENAME to the php executable if you use ScriptAlias configurations, and the proper path is in PATH_TRANSLATED. SCRIPT_NAME in this is faked, but that is ok, Apache sets SCRIPT_NAME to the ScriptAlias of the executable. --REQUEST-- return <<<END PATH_INFO=/path/info END; --ENV-- return <<<END REDIRECT_URL=$scriptname PATH_TRANSLATED=$filename/path/info PATH_INFO=$scriptname/path/info SCRIPT_NAME=/scriptalias/php SCRIPT_FILENAME=$this->conf['TEST_PHP_EXECUTABLE'] END; --CGI-- --FILE-- <?php echo $_SERVER['PATH_INFO']; ?> --EXPECT-- /path/info Index: php4/sapi/tests/test005.phpt +++ php4/sapi/tests/test005.phpt --TEST-- QUERY_STRING Security Bug --DESCRIPTION-- This bug was present in PHP 4.3.0 only. A failure should print HELLO. --REQUEST-- return <<<END SCRIPT_NAME=/nothing.php QUERY_STRING=$filename END; --ENV-- return <<<END REDIRECT_URL=$scriptname PATH_TRANSLATED=c:\apache\1.3.27\htdocs\nothing.php QUERY_STRING=$filename PATH_INFO=/nothing.php SCRIPT_NAME=/phpexe/php.exe/nothing.php SCRIPT_FILENAME=c:\apache\1.3.27\htdocs\nothing.php END; --CGI-- --FILE-- <?php echo "HELLO"; ?> --EXPECTHEADERS-- Status: 404 --EXPECT-- No input file specified. Index: php4/sapi/tests/test006.phpt +++ php4/sapi/tests/test006.phpt --TEST-- Multipart Form POST Data --CGI-- --HEADERS-- return <<<END Content-Type=multipart/form-data; boundary=---------------------------240723202011929 Content-Length=862 END; --ENV-- return <<<END CONTENT_TYPE=multipart/form-data; boundary=---------------------------240723202011929 CONTENT_LENGTH=862 END; --POST-- -----------------------------240723202011929 Content-Disposition: form-data; name="entry" entry box -----------------------------240723202011929 Content-Disposition: form-data; name="password" password box -----------------------------240723202011929 Content-Disposition: form-data; name="radio1" test 1 -----------------------------240723202011929 Content-Disposition: form-data; name="checkbox1" test 1 -----------------------------240723202011929 Content-Disposition: form-data; name="choices" Choice 1 -----------------------------240723202011929 Content-Disposition: form-data; name="choices" Choice 2 -----------------------------240723202011929 Content-Disposition: form-data; name="file"; filename="info.php" Content-Type: application/octet-stream <?php phpinfo(); ?> -----------------------------240723202011929-- --GET-- --FILE-- <?php error_reporting(0); print_r($_POST); print_r($_FILES); ?> --EXPECTF-- Array ( [entry] => entry box [password] => password box [radio1] => test 1 [checkbox1] => test 1 [choices] => Choice 2 ) Array ( [file] => Array ( [name] => info.php [type] => application/octet-stream [tmp_name] => %s [error] => 0 [size] => 21 ) ) Index: php4/sapi/tests/test007.phpt +++ php4/sapi/tests/test007.phpt --TEST-- Multipart Form POST Data, incorrect content length --CGI-- --HEADERS-- return <<<END Content-Type=multipart/form-data; boundary=---------------------------240723202011929 Content-Length=100 END; --POST-- -----------------------------240723202011929 Content-Disposition: form-data; name="entry" entry box -----------------------------240723202011929 Content-Disposition: form-data; name="password" password box -----------------------------240723202011929 Content-Disposition: form-data; name="radio1" test 1 -----------------------------240723202011929 Content-Disposition: form-data; name="checkbox1" test 1 -----------------------------240723202011929 Content-Disposition: form-data; name="choices" Choice 1 -----------------------------240723202011929 Content-Disposition: form-data; name="choices" Choice 2 -----------------------------240723202011929 Content-Disposition: form-data; name="file"; filename="info.php" Content-Type: application/octet-stream <?php phpinfo(); ?> -----------------------------240723202011929-- --GET-- --FILE-- <?php print @$_POST['choices']; ?> --EXPECT--
« previous php.cvs (#19762) next »