Changed the names to match the PECL nomenclature
[phpCairo.git] / src / cairo / run-tests.php
blob7b3880764f70f82b7186e0dd0330f7f7c7b34f10
1 <?php
2 /*
3 +----------------------------------------------------------------------+
4 | PHP Version 5 |
5 +----------------------------------------------------------------------+
6 | Copyright (c) 1997-2007 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 <iliaa@php.net> |
17 | Preston L. Bannister <pbannister@php.net> |
18 | Marcus Boerger <helly@php.net> |
19 | Derick Rethans <derick@php.net> |
20 | Sander Roobol <sander@php.net> |
21 | (based on version by: Stig Bakken <ssb@php.net>) |
22 | (based on the PHP 3 test framework by Rasmus Lerdorf) |
23 +----------------------------------------------------------------------+
26 /* $Id: run-tests.php,v 1.226.2.37.2.35 2007/09/14 15:28:03 nlopess Exp $ */
28 /* Sanity check to ensure that pcre extension needed by this script is available.
29 * In the event it is not, print a nice error message indicating that this script will
30 * not run without it.
32 if (!extension_loaded("pcre")) {
33 echo <<<NO_PCRE_ERROR
35 +-----------------------------------------------------------+
36 | ! ERROR ! |
37 | The test-suite requires that you have pcre extension |
38 | enabled. To enable this extension either compile your PHP |
39 | with --with-pcre-regex or if you've compiled pcre as a |
40 | shared module load it via php.ini. |
41 +-----------------------------------------------------------+
43 NO_PCRE_ERROR;
44 exit;
47 if (!function_exists("proc_open")) {
48 echo <<<NO_PROC_OPEN_ERROR
50 +-----------------------------------------------------------+
51 | ! ERROR ! |
52 | The test-suite requires that proc_open() is available. |
53 | Please check if you disabled it in php.ini. |
54 +-----------------------------------------------------------+
56 NO_PROC_OPEN_ERROR;
57 exit;
60 // store current directory
61 $CUR_DIR = getcwd();
63 // change into the PHP source directory.
65 if (getenv('TEST_PHP_SRCDIR')) {
66 @chdir(getenv('TEST_PHP_SRCDIR'));
69 // Delete some security related environment variables
70 putenv('SSH_CLIENT=deleted');
71 putenv('SSH_AUTH_SOCK=deleted');
72 putenv('SSH_TTY=deleted');
73 putenv('SSH_CONNECTION=deleted');
75 $cwd = getcwd();
76 set_time_limit(0);
78 // delete as much output buffers as possible
79 while(@ob_end_clean());
80 if (ob_get_level()) echo "Not all buffers were deleted.\n";
82 error_reporting(E_ALL);
83 ini_set('magic_quotes_runtime',0); // this would break tests by modifying EXPECT sections
85 if (ini_get('safe_mode')) {
86 echo <<< SAFE_MODE_WARNING
88 +-----------------------------------------------------------+
89 | ! WARNING ! |
90 | You are running the test-suite with "safe_mode" ENABLED ! |
91 | |
92 | Chances are high that no test will work at all, |
93 | depending on how you configured "safe_mode" ! |
94 +-----------------------------------------------------------+
97 SAFE_MODE_WARNING;
100 $environment = isset($_ENV) ? $_ENV : array();
102 // Don't ever guess at the PHP executable location.
103 // Require the explicit specification.
104 // Otherwise we could end up testing the wrong file!
106 if (getenv('TEST_PHP_EXECUTABLE')) {
107 $php = getenv('TEST_PHP_EXECUTABLE');
108 if ($php=='auto') {
109 $php = $cwd.'/sapi/cli/php';
110 putenv("TEST_PHP_EXECUTABLE=$php");
112 $environment['TEST_PHP_EXECUTABLE'] = $php;
115 if (getenv('TEST_PHP_CGI_EXECUTABLE')) {
116 $php_cgi = getenv('TEST_PHP_CGI_EXECUTABLE');
117 if ($php_cgi=='auto') {
118 $php_cgi = $cwd.'/sapi/cgi/php-cgi';
119 putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi");
121 $environment['TEST_PHP_CGI_EXECUTABLE'] = $php_cgi;
124 if ($argc !=2 || ($argv[1] != '-h' && $argv[1] != '-help' && $argv != '--help'))
126 if (empty($php) || !file_exists($php)) {
127 error("environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!");
129 if (function_exists('is_executable') && !@is_executable($php)) {
130 error("invalid PHP executable specified by TEST_PHP_EXECUTABLE = " . $php);
134 if (getenv('TEST_PHP_LOG_FORMAT')) {
135 $log_format = strtoupper(getenv('TEST_PHP_LOG_FORMAT'));
136 } else {
137 $log_format = 'LEOD';
140 // Check whether a detailed log is wanted.
141 if (getenv('TEST_PHP_DETAILED')) {
142 $DETAILED = getenv('TEST_PHP_DETAILED');
143 } else {
144 $DETAILED = 0;
147 // Check whether user test dirs are requested.
148 if (getenv('TEST_PHP_USER')) {
149 $user_tests = explode (',', getenv('TEST_PHP_USER'));
150 } else {
151 $user_tests = array();
154 $exts_to_test = array();
155 $ini_overwrites = array(
156 'output_handler=',
157 'open_basedir=',
158 'safe_mode=0',
159 'disable_functions=',
160 'output_buffering=Off',
161 'error_reporting=8191',
162 'display_errors=1',
163 'display_startup_errors=1',
164 'log_errors=0',
165 'html_errors=0',
166 'track_errors=1',
167 'report_memleaks=1',
168 'report_zend_debug=0',
169 'docref_root=',
170 'docref_ext=.html',
171 'error_prepend_string=',
172 'error_append_string=',
173 'auto_prepend_file=',
174 'auto_append_file=',
175 'magic_quotes_runtime=0',
178 function write_information($show_html)
180 global $cwd, $php, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test;
182 // Get info from php
183 $info_file = realpath(dirname(__FILE__)) . '/run-test-info.php';
184 @unlink($info_file);
185 $php_info = '<?php echo "
186 PHP_SAPI : " . PHP_SAPI . "
187 PHP_VERSION : " . phpversion() . "
188 ZEND_VERSION: " . zend_version() . "
189 PHP_OS : " . PHP_OS . " - " . php_uname() . "
190 INI actual : " . realpath(get_cfg_var("cfg_file_path")) . "
191 More .INIs : " . (function_exists(\'php_ini_scanned_files\') ? str_replace("\n","", php_ini_scanned_files()) : "** not determined **"); ?>';
192 save_text($info_file, $php_info);
193 $info_params = array();
194 settings2array($ini_overwrites,$info_params);
195 settings2params($info_params);
196 $php_info = `$php $pass_options $info_params "$info_file"`;
197 @unlink($info_file);
198 define('TESTED_PHP_VERSION', `$php $pass_options -r "echo PHP_VERSION;"`);
200 // load list of enabled extensions
201 save_text($info_file, '<?php echo join(",",get_loaded_extensions()); ?>');
202 $exts_to_test = explode(',',`$php $pass_options $info_params "$info_file"`);
203 // check for extensions that need special handling and regenerate
204 $info_params_ex = array(
205 'session' => array('session.auto_start=0'),
206 'tidy' => array('tidy.clean_output=0'),
207 'zlib' => array('zlib.output_compression=Off'),
208 'xdebug' => array('xdebug.default_enable=0'),
210 foreach($info_params_ex as $ext => $ini_overwrites_ex) {
211 if (in_array($ext, $exts_to_test)) {
212 $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex);
215 @unlink($info_file);
217 // Write test context information.
218 echo "
219 =====================================================================
220 CWD : $cwd
221 PHP : $php $php_info
222 Extra dirs : ";
223 foreach ($user_tests as $test_dir) {
224 echo "{$test_dir}\n ";
226 echo "
227 =====================================================================
231 // Determine the tests to be run.
233 $test_files = array();
234 $redir_tests = array();
235 $test_results = array();
236 $PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array());
238 // If parameters given assume they represent selected tests to run.
239 $failed_tests_file= false;
240 $pass_option_n = false;
241 $pass_options = '';
243 $compression = 0;
244 $output_file = $CUR_DIR . '/php_test_results_' . @date('Ymd_Hi') . '.txt';
245 if ($compression) {
246 $output_file = 'compress.zlib://' . $output_file . '.gz';
248 $just_save_results = false;
249 $leak_check = false;
250 $html_output = false;
251 $html_file = null;
252 $temp_source = null;
253 $temp_target = null;
254 $temp_urlbase = null;
255 $conf_passed = null;
256 $no_clean = false;
258 $cfgtypes = array('show', 'keep');
259 $cfgfiles = array('skip', 'php', 'clean');
260 $cfg = array();
261 foreach($cfgtypes as $type) {
262 $cfg[$type] = array();
263 foreach($cfgfiles as $file) {
264 $cfg[$type][$file] = false;
268 if (getenv('TEST_PHP_ARGS'))
270 if (!isset($argc) || !$argc || !isset($argv))
272 $argv = array(__FILE__);
274 $argv = array_merge($argv, split(' ', getenv('TEST_PHP_ARGS')));
275 $argc = count($argv);
278 if (isset($argc) && $argc > 1) {
279 for ($i=1; $i<$argc; $i++) {
280 $is_switch = false;
281 $switch = substr($argv[$i],1,1);
282 $repeat = substr($argv[$i],0,1) == '-';
283 while ($repeat) {
284 $repeat = false;
285 if (!$is_switch) {
286 $switch = substr($argv[$i],1,1);
288 $is_switch = true;
289 switch($switch) {
290 case 'r':
291 case 'l':
292 $test_list = @file($argv[++$i]);
293 if ($test_list) {
294 foreach($test_list as $test) {
295 $matches = array();
296 if (preg_match('/^#.*\[(.*)\]\:\s+(.*)$/', $test, $matches)) {
297 $redir_tests[] = array($matches[1], $matches[2]);
298 } else if (strlen($test)) {
299 $test_files[] = trim($test);
303 if ($switch != 'l') {
304 break;
306 $i--;
307 // break left intentionally
308 case 'w':
309 $failed_tests_file = fopen($argv[++$i], 'w+t');
310 break;
311 case 'a':
312 $failed_tests_file = fopen($argv[++$i], 'a+t');
313 break;
314 case 'c':
315 $conf_passed = $argv[++$i];
316 break;
317 case 'd':
318 $ini_overwrites[] = $argv[++$i];
319 break;
320 //case 'h'
321 case '--keep-all':
322 foreach($cfgfiles as $file) {
323 $cfg['keep'][$file] = true;
325 break;
326 case '--keep-skip':
327 $cfg['keep']['skip'] = true;
328 break;
329 case '--keep-php':
330 $cfg['keep']['php'] = true;
331 break;
332 case '--keep-clean':
333 $cfg['keep']['clean'] = true;
334 break;
335 //case 'l'
336 case 'm':
337 $leak_check = true;
338 break;
339 case 'n':
340 if (!$pass_option_n) {
341 $pass_options .= ' -n';
343 $pass_option_n = true;
344 break;
345 case 'N':
346 // this is always native
347 break;
348 case '--no-clean':
349 $no_clean = true;
350 break;
351 case 'q':
352 putenv('NO_INTERACTION=1');
353 break;
354 //case 'r'
355 case 's':
356 $output_file = $argv[++$i];
357 $just_save_results = true;
358 break;
359 case '--show-all':
360 foreach($cfgfiles as $file) {
361 $cfg['show'][$file] = true;
363 break;
364 case '--show-skip':
365 $cfg['show']['skip'] = true;
366 break;
367 case '--show-php':
368 $cfg['show']['php'] = true;
369 break;
370 case '--show-clean':
371 $cfg['show']['clean'] = true;
372 break;
373 case '--temp-source':
374 $temp_source = $argv[++$i];
375 break;
376 case '--temp-target':
377 $temp_target = $argv[++$i];
378 if ($temp_urlbase) {
379 $temp_urlbase = $temp_target;
381 break;
382 case '--temp-urlbase':
383 $temp_urlbase = $argv[++$i];
384 break;
385 case 'v':
386 case '--verbose':
387 $DETAILED = true;
388 break;
389 //case 'w'
390 case '-':
391 // repeat check with full switch
392 $switch = $argv[$i];
393 if ($switch != '-') {
394 $repeat = true;
396 break;
397 case '--html':
398 $html_file = @fopen($argv[++$i], 'wt');
399 $html_output = is_resource($html_file);
400 break;
401 case '--version':
402 echo '$Revision: 1.226.2.37.2.35 $'."\n";
403 exit(1);
405 case 'u':
406 case 'U':
407 // Allow using u or U for forward compatibility
408 break;
410 default:
411 echo "Illegal switch '$switch' specified!\n";
412 case 'h':
413 case '-help':
414 case '--help':
415 echo <<<HELP
416 Synopsis:
417 php run-tests.php [options] [files] [directories]
419 Options:
420 -l <file> Read the testfiles to be executed from <file>. After the test
421 has finished all failed tests are written to the same <file>.
422 If the list is empty and no further test is specified then
423 all tests are executed (same as: -r <file> -w <file>).
425 -r <file> Read the testfiles to be executed from <file>.
427 -w <file> Write a list of all failed tests to <file>.
429 -a <file> Same as -w but append rather then truncating <file>.
431 -c <file> Look for php.ini in directory <file> or use <file> as ini.
433 -n Pass -n option to the php binary (Do not use a php.ini).
435 -d foo=bar Pass -d option to the php binary (Define INI entry foo
436 with value 'bar').
438 -m Test for memory leaks with Valgrind.
440 -N Always set (Test with unicode_semantics set off in PHP 6).
442 -s <file> Write output to <file>.
444 -q Quiet, no user interaction (same as environment NO_INTERACTION).
446 --verbose
447 -v Verbose mode.
449 --help
450 -h This Help.
452 --html <file> Generate HTML output.
454 --temp-source <sdir> --temp-target <tdir> [--temp-urlbase <url>]
455 Write temporary files to <tdir> by replacing <sdir> from the
456 filenames to generate with <tdir>. If --html is being used and
457 <url> given then the generated links are relative and prefixed
458 with the given url. In general you want to make <sdir> the path
459 to your source files and <tdir> some pach in your web page
460 hierarchy with <url> pointing to <tdir>.
462 --keep-[all|php|skip|clean]
463 Do not delete 'all' files, 'php' test file, 'skip' or 'clean'
464 file.
466 --show-[all|php|skip|clean]
467 Show 'all' files, 'php' test file, 'skip' or 'clean' file.
469 --no-clean Do not execute clean section if any.
471 HELP;
472 exit(1);
475 if (!$is_switch) {
476 $testfile = realpath($argv[$i]);
477 if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) {
478 if (preg_match("/\.phpt$/", $argv[$i])) {
479 $pattern_match = glob($argv[$i]);
480 } else if (preg_match("/\*$/", $argv[$i])) {
481 $pattern_match = glob($argv[$i] . '.phpt');
482 } else {
483 die("bogus test name " . $argv[$i] . "\n");
485 if (is_array($pattern_match)) {
486 $test_files = array_merge($test_files, $pattern_match);
488 } else if (is_dir($testfile)) {
489 find_files($testfile);
490 } else if (preg_match("/\.phpt$/", $testfile)) {
491 $test_files[] = $testfile;
492 } else {
493 die("bogus test name " . $argv[$i] . "\n");
497 if (strlen($conf_passed))
499 $pass_options .= " -c '$conf_passed'";
501 $test_files = array_unique($test_files);
502 $test_files = array_merge($test_files, $redir_tests);
504 // Run selected tests.
505 $test_cnt = count($test_files);
506 if ($test_cnt) {
507 write_information($html_output);
508 usort($test_files, "test_sort");
509 $start_time = time();
510 if (!$html_output) {
511 echo "Running selected tests.\n";
512 } else {
513 show_start($start_time);
515 $test_idx = 0;
516 run_all_tests($test_files, $environment);
517 $end_time = time();
518 if ($html_output) {
519 show_end($end_time);
521 if ($failed_tests_file) {
522 fclose($failed_tests_file);
524 if (count($test_files) || count($test_results)) {
525 compute_summary();
526 if ($html_output) {
527 fwrite($html_file, "<hr/>\n" . get_summary(false, true));
529 echo "=====================================================================";
530 echo get_summary(false, false);
532 if ($html_output) {
533 fclose($html_file);
535 if (getenv('REPORT_EXIT_STATUS') == 1 and preg_match('/FAILED(?: |$)/', implode(' ', $test_results))) {
536 exit(1);
538 exit(0);
542 write_information($html_output);
544 // Compile a list of all test files (*.phpt).
545 $test_files = array();
546 $exts_tested = count($exts_to_test);
547 $exts_skipped = 0;
548 $ignored_by_ext = 0;
549 sort($exts_to_test);
550 $test_dirs = array();
551 $optionals = array('tests', 'ext', 'Zend', 'ZendEngine2', 'sapi/cli', 'sapi/cgi');
552 foreach($optionals as $dir) {
553 if (@filetype($dir) == 'dir') {
554 $test_dirs[] = $dir;
558 // Convert extension names to lowercase
559 foreach ($exts_to_test as $key => $val) {
560 $exts_to_test[$key] = strtolower($val);
563 foreach ($test_dirs as $dir) {
564 find_files("{$cwd}/{$dir}", ($dir == 'ext'));
567 foreach ($user_tests as $dir) {
568 find_files($dir, ($dir == 'ext'));
571 function find_files($dir,$is_ext_dir=FALSE,$ignore=FALSE)
573 global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped, $exts_tested;
575 $o = opendir($dir) or error("cannot open directory: $dir");
576 while (($name = readdir($o)) !== FALSE) {
577 if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', 'CVS'))) {
578 $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test));
579 if ($skip_ext) {
580 $exts_skipped++;
582 find_files("{$dir}/{$name}", FALSE, $ignore || $skip_ext);
585 // Cleanup any left-over tmp files from last run.
586 if (substr($name, -4) == '.tmp') {
587 @unlink("$dir/$name");
588 continue;
591 // Otherwise we're only interested in *.phpt files.
592 if (substr($name, -5) == '.phpt') {
593 if ($ignore) {
594 $ignored_by_ext++;
595 } else {
596 $testfile = realpath("{$dir}/{$name}");
597 $test_files[] = $testfile;
601 closedir($o);
604 function test_name($name)
606 if (is_array($name)) {
607 return $name[0] . ':' . $name[1];
608 } else {
609 return $name;
613 function test_sort($a, $b)
615 global $cwd;
617 $a = test_name($a);
618 $b = test_name($b);
620 $ta = strpos($a, "{$cwd}/tests")===0 ? 1 + (strpos($a, "{$cwd}/tests/run-test")===0 ? 1 : 0) : 0;
621 $tb = strpos($b, "{$cwd}/tests")===0 ? 1 + (strpos($b, "{$cwd}/tests/run-test")===0 ? 1 : 0) : 0;
622 if ($ta == $tb) {
623 return strcmp($a, $b);
624 } else {
625 return $tb - $ta;
629 $test_files = array_unique($test_files);
630 usort($test_files, "test_sort");
632 $start_time = time();
633 show_start($start_time);
635 $test_cnt = count($test_files);
636 $test_idx = 0;
637 run_all_tests($test_files, $environment);
638 $end_time = time();
639 if ($failed_tests_file) {
640 fclose($failed_tests_file);
643 // Summarize results
645 if (0 == count($test_results)) {
646 echo "No tests were run.\n";
647 return;
650 compute_summary();
652 show_end($end_time);
653 show_summary();
655 if ($html_output) {
656 fclose($html_file);
659 define('PHP_QA_EMAIL', 'qa-reports@lists.php.net');
660 define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php');
662 /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */
663 if (false) {
664 $fp = fopen("php://stdin", "r+");
665 if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED']) {
666 echo "\nYou may have found a problem in PHP.";
668 echo "\nWe would like to send this report automatically to the\n";
669 echo "PHP QA team, to give us a better understanding of how\nthe test cases are doing. If you don't want to send it\n";
670 echo "immediately, you can choose \"s\" to save the report to\na file that you can send us later.\n";
671 echo "Do you want to send this report now? [Yns]: ";
672 flush();
673 $user_input = fgets($fp, 10);
674 $just_save_results = (strtolower($user_input[0]) == 's');
676 if ($just_save_results || false) {
677 if ($just_save_results || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') {
679 * Collect information about the host system for our report
680 * Fetch phpinfo() output so that we can see the PHP enviroment
681 * Make an archive of all the failed tests
682 * Send an email
684 if ($just_save_results)
686 $user_input = 's';
688 /* Ask the user to provide an email address, so that QA team can contact the user */
689 if (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) {
690 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): ";
691 flush();
692 $user_email = trim(fgets($fp, 1024));
693 $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email));
696 $failed_tests_data = '';
697 $sep = "\n" . str_repeat('=', 80) . "\n";
699 $failed_tests_data .= $failed_test_summary . "\n";
700 $failed_tests_data .= get_summary(true, false) . "\n";
702 if ($sum_results['FAILED']) {
703 foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) {
704 $failed_tests_data .= $sep . $test_info['name'] . $test_info['info'];
705 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output']));
706 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff']));
707 $failed_tests_data .= $sep . "\n\n";
709 $status = "failed";
710 } else {
711 $status = "success";
714 $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep;
715 $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n";
716 $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A';
718 if (substr(PHP_OS, 0, 3) != "WIN") {
719 /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */
720 if (getenv('PHP_AUTOCONF')) {
721 $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version');
722 } else {
723 $autoconf = shell_exec('autoconf --version');
726 /* Always use the generated libtool - Mac OSX uses 'glibtool' */
727 $libtool = shell_exec($CUR_DIR . '/libtool --version');
729 /* Use shtool to find out if there is glibtool present (MacOSX) */
730 $sys_libtool_path = shell_exec(dirname(__FILE__) . '/build/shtool path glibtool libtool');
731 if ($sys_libtool_path) {
732 $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version');
735 /* Try the most common flags for 'version' */
736 $flags = array('-v', '-V', '--version');
737 $cc_status=0;
738 foreach($flags AS $flag) {
739 system(getenv('CC')." $flag >/dev/null 2>&1", $cc_status);
740 if ($cc_status == 0) {
741 $compiler = shell_exec(getenv('CC')." $flag 2>&1");
742 break;
745 $ldd = shell_exec("ldd $php 2>/dev/null");
747 $failed_tests_data .= "Autoconf:\n$autoconf\n";
748 $failed_tests_data .= "Bundled Libtool:\n$libtool\n";
749 $failed_tests_data .= "System Libtool:\n$sys_libtool\n";
750 $failed_tests_data .= "Compiler:\n$compiler\n";
751 $failed_tests_data .= "Bison:\n". @shell_exec('bison --version 2>/dev/null'). "\n";
752 $failed_tests_data .= "Libraries:\n$ldd\n";
753 $failed_tests_data .= "\n";
755 if (isset($user_email)) {
756 $failed_tests_data .= "User's E-mail: ".$user_email."\n\n";
759 $failed_tests_data .= $sep . "PHPINFO" . $sep;
760 $failed_tests_data .= shell_exec($php.' -dhtml_errors=0 -i');
762 if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status)) {
763 file_put_contents($output_file, $failed_tests_data);
765 if (!$just_save_results) {
766 echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n";
769 echo "Please send ".$output_file." to ".PHP_QA_EMAIL." manually, thank you.\n";
770 } else {
771 fwrite($fp, "\nThank you for helping to make PHP better.\n");
772 fclose($fp);
777 if (getenv('REPORT_EXIT_STATUS') == 1 and $sum_results['FAILED']) {
778 exit(1);
780 exit(0);
783 // Send Email to QA Team
786 function mail_qa_team($data, $compression, $status = FALSE)
788 $url_bits = parse_url(QA_SUBMISSION_PAGE);
789 if (empty($url_bits['port'])) $url_bits['port'] = 80;
791 $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data)));
792 $data_length = strlen($data);
794 $fs = fsockopen($url_bits['host'], $url_bits['port'], $errno, $errstr, 10);
795 if (!$fs) {
796 return FALSE;
799 $php_version = urlencode(TESTED_PHP_VERSION);
801 echo "\nPosting to {$url_bits['host']} {$url_bits['path']}\n";
802 fwrite($fs, "POST ".$url_bits['path']."?status=$status&version=$php_version HTTP/1.1\r\n");
803 fwrite($fs, "Host: ".$url_bits['host']."\r\n");
804 fwrite($fs, "User-Agent: QA Browser 0.1\r\n");
805 fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n");
806 fwrite($fs, "Content-Length: ".$data_length."\r\n\r\n");
807 fwrite($fs, $data);
808 fwrite($fs, "\r\n\r\n");
809 fclose($fs);
811 return 1;
816 // Write the given text to a temporary file, and return the filename.
819 function save_text($filename, $text, $filename_copy = null)
821 global $DETAILED;
823 if ($filename_copy && $filename_copy != $filename) {
824 if (@file_put_contents($filename_copy, $text) === false) {
825 error("Cannot open file '" . $filename_copy . "' (save_text)");
828 if (@file_put_contents($filename, $text) === false) {
829 error("Cannot open file '" . $filename . "' (save_text)");
831 if (1 < $DETAILED) echo "
832 FILE $filename {{{
833 $text
834 }}}
839 // Write an error in a format recognizable to Emacs or MSVC.
842 function error_report($testname, $logname, $tested)
844 $testname = realpath($testname);
845 $logname = realpath($logname);
846 switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) {
847 case 'MSVC':
848 echo $testname . "(1) : $tested\n";
849 echo $logname . "(1) : $tested\n";
850 break;
851 case 'EMACS':
852 echo $testname . ":1: $tested\n";
853 echo $logname . ":1: $tested\n";
854 break;
858 function system_with_timeout($commandline, $env = null, $stdin = null)
860 global $leak_check;
862 $data = "";
864 $proc = proc_open($commandline, array(
865 0 => array('pipe', 'r'),
866 1 => array('pipe', 'w'),
867 2 => array('pipe', 'w')
868 ), $pipes, null, $env, array("suppress_errors" => true));
870 if (!$proc)
871 return false;
873 if (is_string($stdin)) {
874 fwrite($pipes[0], $stdin);
876 fclose($pipes[0]);
878 while (true) {
879 /* hide errors from interrupted syscalls */
880 $r = $pipes;
881 $w = null;
882 $e = null;
883 $n = @stream_select($r, $w, $e, $leak_check ? 300 : 60);
885 if ($n === 0) {
886 /* timed out */
887 $data .= "\n ** ERROR: process timed out **\n";
888 proc_terminate($proc);
889 return $data;
890 } else if ($n > 0) {
891 $line = fread($pipes[1], 8192);
892 if (strlen($line) == 0) {
893 /* EOF */
894 break;
896 $data .= $line;
899 $stat = proc_get_status($proc);
900 if ($stat['signaled']) {
901 $data .= "\nTermsig=".$stat['stopsig'];
903 $code = proc_close($proc);
904 return $data;
907 function run_all_tests($test_files, $env, $redir_tested = NULL)
909 global $test_results, $failed_tests_file, $php, $test_cnt, $test_idx;
911 foreach($test_files as $name)
913 if (is_array($name))
915 $index = "# $name[1]: $name[0]";
916 if ($redir_tested)
918 $name = $name[0];
921 else if ($redir_tested)
923 $index = "# $redir_tested: $name";
925 else
927 $index = $name;
929 $test_idx++;
930 $result = run_test($php, $name, $env);
931 if (!is_array($name) && $result != 'REDIR')
933 $test_results[$index] = $result;
934 if ($failed_tests_file && ($result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED'))
936 fwrite($failed_tests_file, "$index\n");
943 // Run an individual test case.
945 function run_test($php, $file, $env)
947 global $log_format, $info_params, $ini_overwrites, $cwd, $PHP_FAILED_TESTS;
948 global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx;
949 global $leak_check, $temp_source, $temp_target, $cfg, $environment;
950 global $no_clean;
952 $temp_filenames = null;
953 $org_file = $file;
955 if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) {
956 $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
959 if (is_array($file)) $file = $file[0];
961 if ($DETAILED) echo "
962 =================
963 TEST $file
966 // Load the sections of the test file.
967 $section_text = array(
968 'TEST' => '',
969 'SKIPIF' => '',
970 'GET' => '',
971 'COOKIE' => '',
972 'POST_RAW' => '',
973 'POST' => '',
974 'UPLOAD' => '',
975 'ARGS' => '',
978 $fp = fopen($file, "rt") or error("Cannot open test file: $file");
980 $borked = false;
981 $bork_info = '';
982 if (!feof($fp)) {
983 $line = fgets($fp);
984 } else {
985 $bork_info = "empty test [$file]";
986 $borked = true;
988 if (strncmp('--TEST--', $line, 8)) {
989 $bork_info = "tests must start with --TEST-- [$file]";
990 $borked = true;
992 $section = 'TEST';
993 $secfile = false;
994 $secdone = false;
995 while (!feof($fp)) {
996 $line = fgets($fp);
998 // Match the beginning of a section.
999 if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
1000 $section = $r[1];
1001 $section_text[$section] = '';
1002 $secfile = $section == 'FILE' || $section == 'FILEEOF';
1003 $secdone = false;
1004 continue;
1007 // Add to the section text.
1008 if (!$secdone) {
1009 $section_text[$section] .= $line;
1012 // End of actual test?
1013 if ($secfile && preg_match('/^===DONE===$/', $line)) {
1014 $secdone = true;
1018 // the redirect section allows a set of tests to be reused outside of
1019 // a given test dir
1020 if (@count($section_text['REDIRECTTEST']) == 1) {
1021 if ($IN_REDIRECT) {
1022 $borked = true;
1023 $bork_info = "Can't redirect a test from within a redirected test";
1024 } else {
1025 $borked = false;
1027 } else {
1028 if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) != 1) {
1029 $bork_info = "missing section --FILE--";
1030 $borked = true;
1032 if (@count($section_text['FILEEOF']) == 1) {
1033 $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']);
1034 unset($section_text['FILEEOF']);
1036 if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) {
1037 $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
1038 $borked = true;
1041 fclose($fp);
1043 $shortname = str_replace($cwd.'/', '', $file);
1044 $tested_file = $shortname;
1046 if ($borked) {
1047 show_result("BORK", $bork_info, $tested_file);
1048 $PHP_FAILED_TESTS['BORKED'][] = array (
1049 'name' => $file,
1050 'test_name' => '',
1051 'output' => '',
1052 'diff' => '',
1053 'info' => "$bork_info [$file]",
1055 return 'BORKED';
1058 $tested = trim($section_text['TEST']);
1060 /* For GET/POST tests, check if cgi sapi is available and if it is, use it. */
1061 if (!empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['COOKIE'])) {
1062 if (isset($php_cgi)) {
1063 $old_php = $php;
1064 $php = $php_cgi .' -C ';
1065 } elseif (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) ."/php-cgi.exe")) {
1066 $old_php = $php;
1067 $php = realpath(dirname($php) ."/php-cgi.exe") .' -C ';
1068 } else {
1069 if (file_exists(dirname($php)."/../../sapi/cgi/php-cgi")) {
1070 $old_php = $php;
1071 $php = realpath(dirname($php)."/../../sapi/cgi/php-cgi") . ' -C ';
1072 } else if (file_exists("./sapi/cgi/php-cgi")) {
1073 $old_php = $php;
1074 $php = realpath("./sapi/cgi/php-cgi") . ' -C ';
1075 } else {
1076 show_result("SKIP", $tested, $tested_file, "reason: CGI not available");
1077 return 'SKIPPED';
1082 show_test($test_idx, $shortname);
1084 if (is_array($IN_REDIRECT)) {
1085 $temp_dir = $test_dir = $IN_REDIRECT['dir'];
1086 } else {
1087 $temp_dir = $test_dir = realpath(dirname($file));
1089 if ($temp_source && $temp_target) {
1090 $temp_dir = str_replace($temp_source, $temp_target, $temp_dir);
1093 $main_file_name = basename($file,'phpt');
1095 $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff';
1096 $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log';
1097 $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp';
1098 $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out';
1099 $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem';
1100 $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php';
1101 $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'php';
1102 $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php';
1103 $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php';
1104 $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php';
1105 $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php';
1106 $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.');
1107 $tmp_relative_file = str_replace(dirname(__FILE__).DIRECTORY_SEPARATOR, '', $test_file) . 't';
1109 if ($temp_source && $temp_target) {
1110 $temp_skipif .= 's';
1111 $temp_file .= 's';
1112 $temp_clean .= 's';
1113 $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file).'.phps';
1114 if (!is_dir(dirname($copy_file))) {
1115 @mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file));
1117 if (isset($section_text['FILE'])) {
1118 save_text($copy_file, $section_text['FILE']);
1120 $temp_filenames = array(
1121 'file' => $copy_file,
1122 'diff' => $diff_filename,
1123 'log' => $log_filename,
1124 'exp' => $exp_filename,
1125 'out' => $output_filename,
1126 'mem' => $memcheck_filename,
1127 'php' => $temp_file,
1128 'skip' => $temp_skipif,
1129 'clean'=> $temp_clean);
1132 if (is_array($IN_REDIRECT)) {
1133 $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']);
1134 $tested_file = $tmp_relative_file;
1135 $section_text['FILE'] = "# original source file: $shortname\n" . $section_text['FILE'];
1138 // unlink old test results
1139 @unlink($diff_filename);
1140 @unlink($log_filename);
1141 @unlink($exp_filename);
1142 @unlink($output_filename);
1143 @unlink($memcheck_filename);
1144 @unlink($temp_file);
1145 @unlink($test_file);
1146 @unlink($temp_skipif);
1147 @unlink($test_skipif);
1148 @unlink($tmp_post);
1149 @unlink($temp_clean);
1150 @unlink($test_clean);
1152 // Reset environment from any previous test.
1153 $env['REDIRECT_STATUS']='';
1154 $env['QUERY_STRING']='';
1155 $env['PATH_TRANSLATED']='';
1156 $env['SCRIPT_FILENAME']='';
1157 $env['REQUEST_METHOD']='';
1158 $env['CONTENT_TYPE']='';
1159 $env['CONTENT_LENGTH']='';
1160 if (!empty($section_text['ENV'])) {
1161 foreach(explode("\n", trim($section_text['ENV'])) as $e) {
1162 $e = explode('=',trim($e),2);
1163 if (!empty($e[0]) && isset($e[1])) {
1164 $env[$e[0]] = $e[1];
1169 // Default ini settings
1170 $ini_settings = array();
1171 // additional ini overwrites
1172 //$ini_overwrites[] = 'setting=value';
1173 settings2array($ini_overwrites, $ini_settings);
1175 // Any special ini settings
1176 // these may overwrite the test defaults...
1177 if (array_key_exists('INI', $section_text)) {
1178 if (strpos($section_text['INI'], '{PWD}') !== false) {
1179 $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
1181 settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings);
1183 settings2params($ini_settings);
1185 // Check if test should be skipped.
1186 $info = '';
1187 $warn = false;
1188 if (array_key_exists('SKIPIF', $section_text)) {
1189 if (trim($section_text['SKIPIF'])) {
1190 if ($cfg['show']['skip']) {
1191 echo "\n========SKIP========\n";
1192 echo $section_text['SKIPIF'];
1193 echo "========DONE========\n";
1195 save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif);
1196 $extra = substr(PHP_OS, 0, 3) !== "WIN" ?
1197 "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
1199 if ($leak_check) {
1200 $env['USE_ZEND_ALLOC'] = '0';
1201 } else {
1202 $env['USE_ZEND_ALLOC'] = '1';
1204 $output = system_with_timeout("$extra $php $pass_options -q $ini_settings $test_skipif", $env);
1205 if (!$cfg['keep']['skip']) {
1206 @unlink($test_skipif);
1208 if (!strncasecmp('skip', ltrim($output), 4)) {
1209 if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) {
1210 show_result("SKIP", $tested, $tested_file, "reason: $m[1]", $temp_filenames);
1211 } else {
1212 show_result("SKIP", $tested, $tested_file, '', $temp_filenames);
1214 if (isset($old_php)) {
1215 $php = $old_php;
1217 if (!$cfg['keep']['skip']) {
1218 @unlink($test_skipif);
1220 return 'SKIPPED';
1222 if (!strncasecmp('info', ltrim($output), 4)) {
1223 if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) {
1224 $info = " (info: $m[1])";
1227 if (!strncasecmp('warn', ltrim($output), 4)) {
1228 if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) {
1229 $warn = true; /* only if there is a reason */
1230 $info = " (warn: $m[1])";
1236 if (@count($section_text['REDIRECTTEST']) == 1) {
1237 $test_files = array();
1239 $IN_REDIRECT = eval($section_text['REDIRECTTEST']);
1240 $IN_REDIRECT['via'] = "via [$shortname]\n\t";
1241 $IN_REDIRECT['dir'] = realpath(dirname($file));
1242 $IN_REDIRECT['prefix'] = trim($section_text['TEST']);
1244 if (@count($IN_REDIRECT['TESTS']) == 1) {
1245 if (is_array($org_file)) {
1246 $test_files[] = $org_file[1];
1247 } else {
1248 $GLOBALS['test_files'] = $test_files;
1249 find_files($IN_REDIRECT['TESTS']);
1250 foreach($GLOBALS['test_files'] as $f) {
1251 $test_files[] = array($f, $file);
1254 $test_cnt += count($test_files) - 1;
1255 $test_idx--;
1257 show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file);
1259 // set up environment
1260 $redirenv = array_merge($environment, $IN_REDIRECT['ENV']);
1261 $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR;
1263 usort($test_files, "test_sort");
1264 run_all_tests($test_files, $redirenv, $tested);
1266 show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file);
1268 // a redirected test never fails
1269 $IN_REDIRECT = false;
1270 return 'REDIR';
1271 } else {
1272 $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory.";
1273 show_result("BORK", $bork_info, '', $temp_filenames);
1274 $PHP_FAILED_TESTS['BORKED'][] = array (
1275 'name' => $file,
1276 'test_name' => '',
1277 'output' => '',
1278 'diff' => '',
1279 'info' => "$bork_info [$file]",
1280 'unicode'=> $unicode_semantics,
1284 if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) {
1285 if (is_array($org_file)) $file = $org_file[0];
1286 $bork_info = "Redirected test did not contain redirection info";
1287 show_result("BORK", $bork_info, '', $temp_filenames);
1288 $PHP_FAILED_TESTS['BORKED'][] = array (
1289 'name' => $file,
1290 'test_name' => '',
1291 'output' => '',
1292 'diff' => '',
1293 'info' => "$bork_info [$file]",
1295 //$test_cnt -= 1; // Only if is_array($org_file) ?
1296 //$test_idx--;
1297 return 'BORKED';
1300 // We've satisfied the preconditions - run the test!
1301 if ($cfg['show']['php']) {
1302 echo "\n========TEST========\n";
1303 echo $section_text['FILE'];
1304 echo "========DONE========\n";
1306 save_text($test_file, $section_text['FILE'], $temp_file);
1307 if (array_key_exists('GET', $section_text)) {
1308 $query_string = trim($section_text['GET']);
1309 } else {
1310 $query_string = '';
1313 $env['REDIRECT_STATUS'] = '1';
1314 $env['QUERY_STRING'] = $query_string;
1315 $env['PATH_TRANSLATED'] = $test_file;
1316 $env['SCRIPT_FILENAME'] = $test_file;
1318 if (array_key_exists('COOKIE', $section_text)) {
1319 $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
1320 } else {
1321 $env['HTTP_COOKIE'] = '';
1324 $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : '';
1326 if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
1327 $post = trim($section_text['POST_RAW']);
1328 $raw_lines = explode("\n", $post);
1330 $request = '';
1331 foreach ($raw_lines as $line) {
1332 if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
1333 $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
1334 continue;
1336 $request .= $line . "\n";
1339 $env['CONTENT_LENGTH'] = strlen($request);
1340 $env['REQUEST_METHOD'] = 'POST';
1342 if (empty($request)) {
1343 return 'BORKED';
1345 save_text($tmp_post, $request);
1346 $cmd = "$php$pass_options$ini_settings -f \"$test_file\" 2>&1 < $tmp_post";
1347 } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
1349 $post = trim($section_text['POST']);
1351 if (array_key_exists('GZIP_POST', $section_text) && function_exists('gzencode')) {
1352 $post = gzencode($post, 9, FORCE_GZIP);
1353 $env['HTTP_CONTENT_ENCODING'] = 'gzip';
1354 } else if (array_key_exists('DEFLATE_POST', $section_text) && function_exists('gzcompress')) {
1355 $post = gzcompress($post, 9);
1356 $env['HTTP_CONTENT_ENCODING'] = 'deflate';
1359 save_text($tmp_post, $post);
1360 $content_length = strlen($post);
1362 $env['REQUEST_METHOD'] = 'POST';
1363 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1364 $env['CONTENT_LENGTH'] = $content_length;
1366 $cmd = "$php$pass_options$ini_settings -f \"$test_file\" 2>&1 < $tmp_post";
1368 } else {
1370 $env['REQUEST_METHOD'] = 'GET';
1371 $env['CONTENT_TYPE'] = '';
1372 $env['CONTENT_LENGTH'] = '';
1374 $cmd = "$php$pass_options$ini_settings -f \"$test_file\" $args 2>&1";
1377 if ($leak_check) {
1378 $env['USE_ZEND_ALLOC'] = '0';
1379 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd";
1380 } else {
1381 $env['USE_ZEND_ALLOC'] = '1';
1384 if ($DETAILED) echo "
1385 CONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . "
1386 CONTENT_TYPE = " . $env['CONTENT_TYPE'] . "
1387 PATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . "
1388 QUERY_STRING = " . $env['QUERY_STRING'] . "
1389 REDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . "
1390 REQUEST_METHOD = " . $env['REQUEST_METHOD'] . "
1391 SCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . "
1392 HTTP_COOKIE = " . $env['HTTP_COOKIE'] . "
1393 COMMAND $cmd
1396 $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null);
1398 if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) {
1399 if (trim($section_text['CLEAN'])) {
1400 if ($cfg['show']['clean']) {
1401 echo "\n========CLEAN=======\n";
1402 echo $section_text['CLEAN'];
1403 echo "========DONE========\n";
1405 save_text($test_clean, trim($section_text['CLEAN']), $temp_clean);
1406 if (!$no_clean) {
1407 $clean_params = array();
1408 settings2array($ini_overwrites,$clean_params);
1409 settings2params($clean_params);
1410 $extra = substr(PHP_OS, 0, 3) !== "WIN" ?
1411 "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
1412 system_with_timeout("$extra $php $pass_options -q $clean_params $test_clean", $env);
1414 if (!$cfg['keep']['clean']) {
1415 @unlink($test_clean);
1420 @unlink($tmp_post);
1422 $leaked = false;
1423 $passed = false;
1425 if ($leak_check) { // leak check
1426 $leaked = @filesize($memcheck_filename) > 0;
1427 if (!$leaked) {
1428 @unlink($memcheck_filename);
1432 // Does the output match what is expected?
1433 $output = str_replace("\r\n", "\n", trim($out));
1435 /* when using CGI, strip the headers from the output */
1436 $headers = "";
1437 if (isset($old_php) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
1438 $output = trim($match[2]);
1439 $rh = preg_split("/[\n\r]+/",$match[1]);
1440 $headers = array();
1441 foreach ($rh as $line) {
1442 if (strpos($line, ':')!==false) {
1443 $line = explode(':', $line, 2);
1444 $headers[trim($line[0])] = trim($line[1]);
1449 $failed_headers = false;
1450 if (isset($section_text['EXPECTHEADERS'])) {
1451 $want = array();
1452 $wanted_headers = array();
1453 $lines = preg_split("/[\n\r]+/",$section_text['EXPECTHEADERS']);
1454 foreach($lines as $line) {
1455 if (strpos($line, ':') !== false) {
1456 $line = explode(':', $line, 2);
1457 $want[trim($line[0])] = trim($line[1]);
1458 $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]);
1461 $org_headers = $headers;
1462 $headers = array();
1463 $output_headers = array();
1464 foreach($want as $k => $v) {
1465 if (isset($org_headers[$k])) {
1466 $headers = $org_headers[$k];
1467 $output_headers[] = $k . ': ' . $org_headers[$k];
1469 if (!isset($org_headers[$k]) || $org_headers[$k] != $v) {
1470 $failed_headers = true;
1473 ksort($wanted_headers);
1474 $wanted_headers = join("\n", $wanted_headers);
1475 ksort($output_headers);
1476 $output_headers = join("\n", $output_headers);
1479 if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
1480 if (isset($section_text['EXPECTF'])) {
1481 $wanted = trim($section_text['EXPECTF']);
1482 } else {
1483 $wanted = trim($section_text['EXPECTREGEX']);
1485 $wanted_re = preg_replace('/\r\n/',"\n",$wanted);
1486 if (isset($section_text['EXPECTF'])) {
1487 $wanted_re = preg_quote($wanted_re, '/');
1488 // Stick to basics
1489 $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re);
1490 $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re);
1491 $wanted_re = str_replace('%a', '.+', $wanted_re);
1492 $wanted_re = str_replace('%w', '\s*', $wanted_re);
1493 $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re);
1494 $wanted_re = str_replace('%d', '\d+', $wanted_re);
1495 $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re);
1496 $wanted_re = str_replace('%f', '[+-]?\.?\d+\.?\d*(?:E-?\d+)?', $wanted_re);
1497 $wanted_re = str_replace('%c', '.', $wanted_re);
1498 // %f allows two points "-.0.0" but that is the best *simple* expression
1500 /* DEBUG YOUR REGEX HERE
1501 var_dump($wanted_re);
1502 print(str_repeat('=', 80) . "\n");
1503 var_dump($output);
1505 if (preg_match("/^$wanted_re\$/s", $output)) {
1506 $passed = true;
1507 if (!$cfg['keep']['php']) {
1508 @unlink($test_file);
1510 if (isset($old_php)) {
1511 $php = $old_php;
1513 if (!$leaked && !$failed_headers) {
1514 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
1515 return 'PASSED';
1518 } else {
1519 $wanted = trim($section_text['EXPECT']);
1520 $wanted = preg_replace('/\r\n/',"\n",$wanted);
1521 // compare and leave on success
1522 if (!strcmp($output, $wanted)) {
1523 $passed = true;
1524 if (!$cfg['keep']['php']) {
1525 @unlink($test_file);
1527 if (isset($old_php)) {
1528 $php = $old_php;
1530 if (!$leaked && !$failed_headers) {
1531 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
1532 return 'PASSED';
1535 $wanted_re = NULL;
1538 // Test failed so we need to report details.
1539 if ($failed_headers) {
1540 $passed = false;
1541 $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted;
1542 $output = $output_headers . "\n--HEADERS--\n" . $output;
1543 if (isset($wanted_re)) {
1544 $wanted_re = $wanted_headers . "\n--HEADERS--\n" . $wanted_re;
1548 if ($leaked) {
1549 $restype[] = 'LEAK';
1551 if ($warn) {
1552 $restype[] = 'WARN';
1554 if (!$passed) {
1555 $restype[] = 'FAIL';
1558 if (!$passed) {
1559 // write .exp
1560 if (strpos($log_format,'E') !== FALSE && file_put_contents($exp_filename, $wanted) === FALSE) {
1561 error("Cannot create expected test output - $exp_filename");
1564 // write .out
1565 if (strpos($log_format,'O') !== FALSE && file_put_contents($output_filename, $output) === FALSE) {
1566 error("Cannot create test output - $output_filename");
1569 // write .diff
1570 if (strpos($log_format,'D') !== FALSE && file_put_contents($diff_filename, generate_diff($wanted,$wanted_re,$output)) === FALSE) {
1571 error("Cannot create test diff - $diff_filename");
1574 // write .log
1575 if (strpos($log_format,'L') !== FALSE && file_put_contents($log_filename, "
1576 ---- EXPECTED OUTPUT
1577 $wanted
1578 ---- ACTUAL OUTPUT
1579 $output
1580 ---- FAILED
1581 ") === FALSE) {
1582 error("Cannot create test log - $log_filename");
1583 error_report($file, $log_filename, $tested);
1587 show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames);
1589 foreach ($restype as $type) {
1590 $PHP_FAILED_TESTS[$type.'ED'][] = array (
1591 'name' => $file,
1592 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]",
1593 'output' => $output_filename,
1594 'diff' => $diff_filename,
1595 'info' => $info,
1599 if (isset($old_php)) {
1600 $php = $old_php;
1603 return $restype[0].'ED';
1606 function comp_line($l1,$l2,$is_reg)
1608 if ($is_reg) {
1609 return preg_match('/^'.$l1.'$/s', $l2);
1610 } else {
1611 return !strcmp($l1, $l2);
1615 function count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$idx2,$cnt1,$cnt2,$steps)
1617 $equal = 0;
1618 while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
1619 $idx1++;
1620 $idx2++;
1621 $equal++;
1622 $steps--;
1624 if (--$steps > 0) {
1625 $eq1 = 0;
1626 $st = $steps / 2;
1627 for ($ofs1 = $idx1+1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) {
1628 $eq = count_array_diff($ar1,$ar2,$is_reg,$w,$ofs1,$idx2,$cnt1,$cnt2,$st);
1629 if ($eq > $eq1) {
1630 $eq1 = $eq;
1633 $eq2 = 0;
1634 $st = $steps;
1635 for ($ofs2 = $idx2+1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) {
1636 $eq = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$ofs2,$cnt1,$cnt2,$st);
1637 if ($eq > $eq2) {
1638 $eq2 = $eq;
1641 if ($eq1 > $eq2) {
1642 $equal += $eq1;
1643 } else if ($eq2 > 0) {
1644 $equal += $eq2;
1647 return $equal;
1650 function generate_array_diff($ar1,$ar2,$is_reg,$w)
1652 $idx1 = 0; $ofs1 = 0; $cnt1 = count($ar1);
1653 $idx2 = 0; $ofs2 = 0; $cnt2 = count($ar2);
1654 $diff = array();
1655 $old1 = array();
1656 $old2 = array();
1658 while ($idx1 < $cnt1 && $idx2 < $cnt2) {
1659 if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
1660 $idx1++;
1661 $idx2++;
1662 continue;
1663 } else {
1664 $c1 = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1+1,$idx2,$cnt1,$cnt2,10);
1665 $c2 = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$idx2+1,$cnt1,$cnt2,10);
1666 if ($c1 > $c2) {
1667 $old1[$idx1] = sprintf("%03d- ", $idx1+1).$w[$idx1++];
1668 $last = 1;
1669 } else if ($c2 > 0) {
1670 $old2[$idx2] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++];
1671 $last = 2;
1672 } else {
1673 $old1[$idx1] = sprintf("%03d- ", $idx1+1).$w[$idx1++];
1674 $old2[$idx2] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++];
1679 reset($old1); $k1 = key($old1); $l1 = -2;
1680 reset($old2); $k2 = key($old2); $l2 = -2;
1681 while ($k1 !== NULL || $k2 !== NULL) {
1682 if ($k1 == $l1+1 || $k2 === NULL) {
1683 $l1 = $k1;
1684 $diff[] = current($old1);
1685 $k1 = next($old1) ? key($old1) : NULL;
1686 } else if ($k2 == $l2+1 || $k1 === NULL) {
1687 $l2 = $k2;
1688 $diff[] = current($old2);
1689 $k2 = next($old2) ? key($old2) : NULL;
1690 } else if ($k1 < $k2) {
1691 $l1 = $k1;
1692 $diff[] = current($old1);
1693 $k1 = next($old1) ? key($old1) : NULL;
1694 } else {
1695 $l2 = $k2;
1696 $diff[] = current($old2);
1697 $k2 = next($old2) ? key($old2) : NULL;
1700 while ($idx1 < $cnt1) {
1701 $diff[] = sprintf("%03d- ", $idx1+1).$w[$idx1++];
1703 while ($idx2 < $cnt2) {
1704 $diff[] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++];
1706 return $diff;
1709 function generate_diff($wanted,$wanted_re,$output)
1711 $w = explode("\n", $wanted);
1712 $o = explode("\n", $output);
1713 $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re);
1714 $diff = generate_array_diff($r,$o,!is_null($wanted_re),$w);
1715 return implode("\r\n", $diff);
1718 function error($message)
1720 echo "ERROR: {$message}\n";
1721 exit(1);
1724 function settings2array($settings, &$ini_settings)
1726 foreach($settings as $setting) {
1727 if (strpos($setting, '=')!==false) {
1728 $setting = explode("=", $setting, 2);
1729 $name = trim(strtolower($setting[0]));
1730 $value = trim($setting[1]);
1731 if ($name == 'extension') {
1732 if (!isset($ini_settings[$name])) {
1733 $ini_settings[$name] = array();
1735 $ini_settings[$name][] = $value;
1736 } else {
1737 $ini_settings[$name] = $value;
1743 function settings2params(&$ini_settings)
1745 $settings = '';
1746 foreach($ini_settings as $name => $value) {
1747 if (is_array($value)) {
1748 foreach($value as $val) {
1749 $val = addslashes($val);
1750 $settings .= " -d \"$name=$val\"";
1752 } else {
1753 $value = addslashes($value);
1754 $settings .= " -d \"$name=$value\"";
1757 $ini_settings = $settings;
1760 function compute_summary()
1762 global $n_total, $test_results, $ignored_by_ext, $sum_results, $percent_results;
1764 $n_total = count($test_results);
1765 $n_total += $ignored_by_ext;
1766 $sum_results = array('PASSED'=>0, 'WARNED'=>0, 'SKIPPED'=>0, 'FAILED'=>0, 'BORKED'=>0, 'LEAKED'=>0);
1767 foreach ($test_results as $v) {
1768 $sum_results[$v]++;
1770 $sum_results['SKIPPED'] += $ignored_by_ext;
1771 $percent_results = array();
1772 while (list($v,$n) = each($sum_results)) {
1773 $percent_results[$v] = (100.0 * $n) / $n_total;
1777 function get_summary($show_ext_summary, $show_html)
1779 global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $leak_check;
1781 $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED'];
1782 if ($x_total) {
1783 $x_warned = (100.0 * $sum_results['WARNED']) / $x_total;
1784 $x_failed = (100.0 * $sum_results['FAILED']) / $x_total;
1785 $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total;
1786 $x_passed = (100.0 * $sum_results['PASSED']) / $x_total;
1787 } else {
1788 $x_warned = $x_failed = $x_passed = $x_leaked = 0;
1791 $summary = "";
1792 if ($show_html) $summary .= "<pre>\n";
1793 if ($show_ext_summary) {
1794 $summary .= "
1795 =====================================================================
1796 TEST RESULT SUMMARY
1797 ---------------------------------------------------------------------
1798 Exts skipped : " . sprintf("%4d",$exts_skipped) . "
1799 Exts tested : " . sprintf("%4d",$exts_tested) . "
1800 ---------------------------------------------------------------------
1803 $summary .= "
1804 Number of tests : " . sprintf("%4d",$n_total). " " . sprintf("%8d",$x_total);
1805 if ($sum_results['BORKED']) {
1806 $summary .= "
1807 Tests borked : " . sprintf("%4d (%5.1f%%)",$sum_results['BORKED'],$percent_results['BORKED']) . " --------";
1809 $summary .= "
1810 Tests skipped : " . sprintf("%4d (%5.1f%%)",$sum_results['SKIPPED'],$percent_results['SKIPPED']) . " --------
1811 Tests warned : " . sprintf("%4d (%5.1f%%)",$sum_results['WARNED'], $percent_results['WARNED']) . " " . sprintf("(%5.1f%%)",$x_warned) . "
1812 Tests failed : " . sprintf("%4d (%5.1f%%)",$sum_results['FAILED'], $percent_results['FAILED']) . " " . sprintf("(%5.1f%%)",$x_failed);
1813 if ($leak_check) {
1814 $summary .= "
1815 Tests leaked : " . sprintf("%4d (%5.1f%%)",$sum_results['LEAKED'], $percent_results['LEAKED']) . " " . sprintf("(%5.1f%%)",$x_leaked);
1817 $summary .= "
1818 Tests passed : " . sprintf("%4d (%5.1f%%)",$sum_results['PASSED'], $percent_results['PASSED']) . " " . sprintf("(%5.1f%%)",$x_passed) . "
1819 ---------------------------------------------------------------------
1820 Time taken : " . sprintf("%4d seconds", $end_time - $start_time) . "
1821 =====================================================================
1823 $failed_test_summary = '';
1824 if (count($PHP_FAILED_TESTS['BORKED'])) {
1825 $failed_test_summary .= "
1826 =====================================================================
1827 BORKED TEST SUMMARY
1828 ---------------------------------------------------------------------
1830 foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) {
1831 $failed_test_summary .= $failed_test_data['info'] . "\n";
1833 $failed_test_summary .= "=====================================================================\n";
1836 if (count($PHP_FAILED_TESTS['FAILED'])) {
1837 $failed_test_summary .= "
1838 =====================================================================
1839 FAILED TEST SUMMARY
1840 ---------------------------------------------------------------------
1842 foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) {
1843 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
1845 $failed_test_summary .= "=====================================================================\n";
1848 if (count($PHP_FAILED_TESTS['LEAKED'])) {
1849 $failed_test_summary .= "
1850 =====================================================================
1851 LEAKED TEST SUMMARY
1852 ---------------------------------------------------------------------
1854 foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) {
1855 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
1857 $failed_test_summary .= "=====================================================================\n";
1860 if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) {
1861 $summary .= $failed_test_summary;
1864 if ($show_html) $summary .= "</pre>";
1866 return $summary;
1869 function show_start($start_time)
1871 global $html_output, $html_file;
1873 if ($html_output)
1875 fwrite($html_file, "<h2>Time Start: " . @date('Y-m-d H:i:s', $start_time) . "</h2>\n");
1876 fwrite($html_file, "<table>\n");
1878 echo "TIME START " . @date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n";
1881 function show_end($end_time)
1883 global $html_output, $html_file;
1885 if ($html_output)
1887 fwrite($html_file, "</table>\n");
1888 fwrite($html_file, "<h2>Time End: " . @date('Y-m-d H:i:s', $end_time) . "</h2>\n");
1890 echo "=====================================================================\nTIME END " . @date('Y-m-d H:i:s', $end_time) . "\n";
1893 function show_summary()
1895 global $html_output, $html_file;
1897 if ($html_output)
1899 fwrite($html_file, "<hr/>\n" . get_summary(true, true));
1901 echo get_summary(true, false);
1904 function show_redirect_start($tests, $tested, $tested_file)
1906 global $html_output, $html_file;
1908 if ($html_output)
1910 fwrite($html_file, "<tr><td colspan='3'>---&gt; $tests ($tested [$tested_file]) begin</td></tr>\n");
1912 echo "---> $tests ($tested [$tested_file]) begin\n";
1915 function show_redirect_ends($tests, $tested, $tested_file)
1917 global $html_output, $html_file;
1919 if ($html_output)
1921 fwrite($html_file, "<tr><td colspan='3'>---&gt; $tests ($tested [$tested_file]) done</td></tr>\n");
1923 echo "---> $tests ($tested [$tested_file]) done\n";
1926 function show_test($test_idx, $shortname)
1928 global $test_cnt;
1930 echo "TEST $test_idx/$test_cnt [$shortname]\r";
1931 flush();
1934 function show_result($result, $tested, $tested_file, $extra = '', $temp_filenames = null)
1936 global $html_output, $html_file, $temp_target, $temp_urlbase;
1938 echo "$result $tested [$tested_file] $extra\n";
1940 if ($html_output)
1942 if (isset($temp_filenames['file']) && @file_exists($temp_filenames['file'])) {
1943 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']);
1944 $tested = "<a href='$url'>$tested</a>";
1946 if (isset($temp_filenames['skip']) && @file_exists($temp_filenames['skip'])) {
1947 if (empty($extra)) {
1948 $extra = "skipif";
1950 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']);
1951 $extra = "<a href='$url'>$extra</a>";
1952 } else if (empty($extra)) {
1953 $extra = "&nbsp;";
1955 if (isset($temp_filenames['diff']) && @file_exists($temp_filenames['diff'])) {
1956 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']);
1957 $diff = "<a href='$url'>diff</a>";
1958 } else {
1959 $diff = "&nbsp;";
1961 if (isset($temp_filenames['mem']) && @file_exists($temp_filenames['mem'])) {
1962 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']);
1963 $mem = "<a href='$url'>leaks</a>";
1964 } else {
1965 $mem = "&nbsp;";
1967 fwrite($html_file,
1968 "<tr>" .
1969 "<td>$result</td>" .
1970 "<td>$tested</td>" .
1971 "<td>$extra</td>" .
1972 "<td>$diff</td>" .
1973 "<td>$mem</td>" .
1974 "</tr>\n");
1979 * Local variables:
1980 * tab-width: 4
1981 * c-basic-offset: 4
1982 * End:
1983 * vim: noet sw=4 ts=4