Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / php / run-tests.php
bloba746c369653ccdbf4bcde6ffb9bee66549ada732
1 #!/usr/bin/env php
2 <?php
3 /*
4 +----------------------------------------------------------------------+
5 | PHP Version 5 |
6 +----------------------------------------------------------------------+
7 | Copyright (c) 1997-2010 The PHP Group |
8 +----------------------------------------------------------------------+
9 | This source file is subject to version 3.01 of the PHP license, |
10 | that is bundled with this package in the file LICENSE, and is |
11 | available through the world-wide-web at the following url: |
12 | http://www.php.net/license/3_01.txt |
13 | If you did not receive a copy of the PHP license and are unable to |
14 | obtain it through the world-wide-web, please send a note to |
15 | license@php.net so we can mail you a copy immediately. |
16 +----------------------------------------------------------------------+
17 | Authors: Ilia Alshanetsky <iliaa@php.net> |
18 | Preston L. Bannister <pbannister@php.net> |
19 | Marcus Boerger <helly@php.net> |
20 | Derick Rethans <derick@php.net> |
21 | Sander Roobol <sander@php.net> |
22 | (based on version by: Stig Bakken <ssb@php.net>) |
23 | (based on the PHP 3 test framework by Rasmus Lerdorf) |
24 +----------------------------------------------------------------------+
27 /* $Id$ */
29 /* Sanity check to ensure that pcre extension needed by this script is available.
30 * In the event it is not, print a nice error message indicating that this script will
31 * not run without it.
34 if (!extension_loaded('pcre')) {
35 echo <<<NO_PCRE_ERROR
37 +-----------------------------------------------------------+
38 | ! ERROR ! |
39 | The test-suite requires that you have pcre extension |
40 | enabled. To enable this extension either compile your PHP |
41 | with --with-pcre-regex or if you've compiled pcre as a |
42 | shared module load it via php.ini. |
43 +-----------------------------------------------------------+
45 NO_PCRE_ERROR;
46 exit;
49 if (!function_exists('proc_open')) {
50 echo <<<NO_PROC_OPEN_ERROR
52 +-----------------------------------------------------------+
53 | ! ERROR ! |
54 | The test-suite requires that proc_open() is available. |
55 | Please check if you disabled it in php.ini. |
56 +-----------------------------------------------------------+
58 NO_PROC_OPEN_ERROR;
59 exit;
62 // Version constants only available as of 5.2.8
63 if (!defined("PHP_VERSION_ID")) {
64 list($major, $minor, $bug) = explode(".", phpversion(), 3);
65 $bug = (int)$bug; // Many distros make up their own versions
66 if ($bug < 10) {
67 $bug = "0$bug";
70 define("PHP_VERSION_ID", "{$major}0{$minor}$bug");
71 define("PHP_MAJOR_VERSION", $major);
74 // __DIR__ is available from 5.3.0
75 if (PHP_VERSION_ID < 50300) {
76 define('__DIR__', realpath(dirname(__FILE__)));
77 // FILE_BINARY is available from 5.2.7
78 if (PHP_VERSION_ID < 50207) {
79 define('FILE_BINARY', 0);
83 // If timezone is not set, use UTC.
84 if (ini_get('date.timezone') == '') {
85 date_default_timezone_set('UTC');
88 // store current directory
89 $CUR_DIR = getcwd();
91 // change into the PHP source directory.
93 if (getenv('TEST_PHP_SRCDIR')) {
94 @chdir(getenv('TEST_PHP_SRCDIR'));
97 // Delete some security related environment variables
98 putenv('SSH_CLIENT=deleted');
99 putenv('SSH_AUTH_SOCK=deleted');
100 putenv('SSH_TTY=deleted');
101 putenv('SSH_CONNECTION=deleted');
103 $cwd = getcwd();
104 set_time_limit(0);
106 ini_set('pcre.backtrack_limit', PHP_INT_MAX);
108 $valgrind_version = 0;
109 $valgrind_header = '';
111 // delete as much output buffers as possible
112 while(@ob_end_clean());
113 if (ob_get_level()) echo "Not all buffers were deleted.\n";
115 error_reporting(E_ALL);
116 if (PHP_MAJOR_VERSION < 6) {
117 ini_set('magic_quotes_runtime',0); // this would break tests by modifying EXPECT sections
118 if (ini_get('safe_mode')) {
119 echo <<< SAFE_MODE_WARNING
121 +-----------------------------------------------------------+
122 | ! WARNING ! |
123 | You are running the test-suite with "safe_mode" ENABLED ! |
125 | Chances are high that no test will work at all, |
126 | depending on how you configured "safe_mode" ! |
127 +-----------------------------------------------------------+
130 SAFE_MODE_WARNING;
134 $environment = isset($_ENV) ? $_ENV : array();
135 if ((substr(PHP_OS, 0, 3) == "WIN") && empty($environment["SystemRoot"])) {
136 $environment["SystemRoot"] = getenv("SystemRoot");
139 // Don't ever guess at the PHP executable location.
140 // Require the explicit specification.
141 // Otherwise we could end up testing the wrong file!
143 $php = null;
144 $php_cgi = null;
146 if (getenv('TEST_PHP_EXECUTABLE')) {
147 $php = getenv('TEST_PHP_EXECUTABLE');
149 if ($php=='auto') {
150 $php = $cwd . '/sapi/cli/php';
151 putenv("TEST_PHP_EXECUTABLE=$php");
153 if (!getenv('TEST_PHP_CGI_EXECUTABLE')) {
154 $php_cgi = $cwd . '/sapi/cgi/php-cgi';
156 if (file_exists($php_cgi)) {
157 putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi");
158 } else {
159 $php_cgi = null;
163 $environment['TEST_PHP_EXECUTABLE'] = $php;
166 if (getenv('TEST_PHP_CGI_EXECUTABLE')) {
167 $php_cgi = getenv('TEST_PHP_CGI_EXECUTABLE');
169 if ($php_cgi=='auto') {
170 $php_cgi = $cwd . '/sapi/cgi/php-cgi';
171 putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi");
174 $environment['TEST_PHP_CGI_EXECUTABLE'] = $php_cgi;
177 function verify_config()
179 global $php;
181 if (empty($php) || !file_exists($php)) {
182 error('environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!');
185 if (function_exists('is_executable') && !is_executable($php)) {
186 error("invalid PHP executable specified by TEST_PHP_EXECUTABLE = $php");
190 if (getenv('TEST_PHP_LOG_FORMAT')) {
191 $log_format = strtoupper(getenv('TEST_PHP_LOG_FORMAT'));
192 } else {
193 $log_format = 'LEODS';
196 // Check whether a detailed log is wanted.
197 if (getenv('TEST_PHP_DETAILED')) {
198 $DETAILED = getenv('TEST_PHP_DETAILED');
199 } else {
200 $DETAILED = 0;
203 junit_init();
205 if (getenv('SHOW_ONLY_GROUPS')) {
206 $SHOW_ONLY_GROUPS = explode(",", getenv('SHOW_ONLY_GROUPS'));
207 } else {
208 $SHOW_ONLY_GROUPS = array();
211 // Check whether user test dirs are requested.
212 if (getenv('TEST_PHP_USER')) {
213 $user_tests = explode (',', getenv('TEST_PHP_USER'));
214 } else {
215 $user_tests = array();
218 $exts_to_test = array();
219 $ini_overwrites = array(
220 'output_handler=',
221 'open_basedir=',
222 'safe_mode=0',
223 'disable_functions=',
224 'output_buffering=Off',
225 'error_reporting=' . (E_ALL | E_STRICT),
226 'display_errors=1',
227 'display_startup_errors=1',
228 'log_errors=0',
229 'html_errors=0',
230 'track_errors=1',
231 'report_memleaks=1',
232 'report_zend_debug=0',
233 'docref_root=',
234 'docref_ext=.html',
235 'error_prepend_string=',
236 'error_append_string=',
237 'auto_prepend_file=',
238 'auto_append_file=',
239 'magic_quotes_runtime=0',
240 'ignore_repeated_errors=0',
241 'precision=14',
242 'memory_limit=128M',
245 function write_information($show_html)
247 global $cwd, $php, $php_cgi, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $leak_check, $valgrind_header;
249 // Get info from php
250 $info_file = __DIR__ . '/run-test-info.php';
251 @unlink($info_file);
252 $php_info = '<?php echo "
253 PHP_SAPI : " , PHP_SAPI , "
254 PHP_VERSION : " , phpversion() , "
255 ZEND_VERSION: " , zend_version() , "
256 PHP_OS : " , PHP_OS , " - " , php_uname() , "
257 INI actual : " , realpath(get_cfg_var("cfg_file_path")) , "
258 More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n","", php_ini_scanned_files()) : "** not determined **"); ?>';
259 save_text($info_file, $php_info);
260 $info_params = array();
261 settings2array($ini_overwrites, $info_params);
262 settings2params($info_params);
263 $php_info = `$php $pass_options $info_params "$info_file"`;
264 define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`);
266 if ($php_cgi && $php != $php_cgi) {
267 $php_info_cgi = `$php_cgi $pass_options $info_params -q "$info_file"`;
268 $php_info_sep = "\n---------------------------------------------------------------------";
269 $php_cgi_info = "$php_info_sep\nPHP : $php_cgi $php_info_cgi$php_info_sep";
270 } else {
271 $php_cgi_info = '';
274 @unlink($info_file);
276 // load list of enabled extensions
277 save_text($info_file, '<?php echo join(",", get_loaded_extensions()); ?>');
278 $exts_to_test = explode(',',`$php $pass_options $info_params "$info_file"`);
279 // check for extensions that need special handling and regenerate
280 $info_params_ex = array(
281 'session' => array('session.auto_start=0'),
282 'tidy' => array('tidy.clean_output=0'),
283 'zlib' => array('zlib.output_compression=Off'),
284 'xdebug' => array('xdebug.default_enable=0'),
285 'mbstring' => array('mbstring.func_overload=0'),
288 foreach($info_params_ex as $ext => $ini_overwrites_ex) {
289 if (in_array($ext, $exts_to_test)) {
290 $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex);
294 @unlink($info_file);
296 // Write test context information.
297 echo "
298 =====================================================================
299 PHP : $php $php_info $php_cgi_info
300 CWD : $cwd
301 Extra dirs : ";
302 foreach ($user_tests as $test_dir) {
303 echo "{$test_dir}\n ";
305 echo "
306 VALGRIND : " . ($leak_check ? $valgrind_header : 'Not used') . "
307 =====================================================================
311 define('PHP_QA_EMAIL', 'qa-reports@lists.php.net');
312 define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php');
313 define('QA_REPORTS_PAGE', 'http://qa.php.net/reports');
315 function save_or_mail_results()
317 global $sum_results, $just_save_results, $failed_test_summary,
318 $PHP_FAILED_TESTS, $CUR_DIR, $php, $output_file, $compression;
320 /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */
321 if (!getenv('NO_INTERACTION')) {
322 $fp = fopen("php://stdin", "r+");
323 if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED'] || $sum_results['XFAILED']) {
324 echo "\nYou may have found a problem in PHP.";
326 echo "\nThis report can be automatically sent to the PHP QA team at\n";
327 echo QA_REPORTS_PAGE . " and http://news.php.net/php.qa.reports\n";
328 echo "This gives us a better understanding of PHP's behavior.\n";
329 echo "If you don't want to send the report immediately you can choose\n";
330 echo "option \"s\" to save it. You can then email it to ". PHP_QA_EMAIL . " later.\n";
331 echo "Do you want to send this report now? [Yns]: ";
332 flush();
334 $user_input = fgets($fp, 10);
335 $just_save_results = (strtolower($user_input[0]) == 's');
338 if ($just_save_results || !getenv('NO_INTERACTION')) {
339 if ($just_save_results || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') {
341 * Collect information about the host system for our report
342 * Fetch phpinfo() output so that we can see the PHP enviroment
343 * Make an archive of all the failed tests
344 * Send an email
346 if ($just_save_results) {
347 $user_input = 's';
350 /* Ask the user to provide an email address, so that QA team can contact the user */
351 if (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) {
352 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): ";
353 flush();
354 $user_email = trim(fgets($fp, 1024));
355 $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email));
358 $failed_tests_data = '';
359 $sep = "\n" . str_repeat('=', 80) . "\n";
360 $failed_tests_data .= $failed_test_summary . "\n";
361 $failed_tests_data .= get_summary(true, false) . "\n";
363 if ($sum_results['FAILED']) {
364 foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) {
365 $failed_tests_data .= $sep . $test_info['name'] . $test_info['info'];
366 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output']), FILE_BINARY);
367 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff']), FILE_BINARY);
368 $failed_tests_data .= $sep . "\n\n";
370 $status = "failed";
371 } else {
372 $status = "success";
375 $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep;
376 $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n";
377 $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A';
379 if (substr(PHP_OS, 0, 3) != "WIN") {
380 /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */
381 if (getenv('PHP_AUTOCONF')) {
382 $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version');
383 } else {
384 $autoconf = shell_exec('autoconf --version');
387 /* Always use the generated libtool - Mac OSX uses 'glibtool' */
388 $libtool = shell_exec($CUR_DIR . '/libtool --version');
390 /* Use shtool to find out if there is glibtool present (MacOSX) */
391 $sys_libtool_path = shell_exec(__DIR__ . '/build/shtool path glibtool libtool');
393 if ($sys_libtool_path) {
394 $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version');
397 /* Try the most common flags for 'version' */
398 $flags = array('-v', '-V', '--version');
399 $cc_status = 0;
401 foreach($flags AS $flag) {
402 system(getenv('CC') . " $flag >/dev/null 2>&1", $cc_status);
403 if ($cc_status == 0) {
404 $compiler = shell_exec(getenv('CC') . " $flag 2>&1");
405 break;
409 $ldd = shell_exec("ldd $php 2>/dev/null");
412 $failed_tests_data .= "Autoconf:\n$autoconf\n";
413 $failed_tests_data .= "Bundled Libtool:\n$libtool\n";
414 $failed_tests_data .= "System Libtool:\n$sys_libtool\n";
415 $failed_tests_data .= "Compiler:\n$compiler\n";
416 $failed_tests_data .= "Bison:\n". shell_exec('bison --version 2>/dev/null') . "\n";
417 $failed_tests_data .= "Libraries:\n$ldd\n";
418 $failed_tests_data .= "\n";
420 if (isset($user_email)) {
421 $failed_tests_data .= "User's E-mail: " . $user_email . "\n\n";
424 $failed_tests_data .= $sep . "PHPINFO" . $sep;
425 $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null');
427 if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status)) {
428 file_put_contents($output_file, $failed_tests_data);
430 if (!$just_save_results) {
431 echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n";
434 echo "Please send " . $output_file . " to " . PHP_QA_EMAIL . " manually, thank you.\n";
435 } else {
436 fwrite($fp, "\nThank you for helping to make PHP better.\n");
437 fclose($fp);
443 // Determine the tests to be run.
445 $test_files = array();
446 $redir_tests = array();
447 $test_results = array();
448 $PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array(), 'XFAILED' => array());
450 // If parameters given assume they represent selected tests to run.
451 $failed_tests_file= false;
452 $pass_option_n = false;
453 $pass_options = '';
455 $compression = 0;
456 $output_file = $CUR_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt';
458 if ($compression) {
459 $output_file = 'compress.zlib://' . $output_file . '.gz';
462 $just_save_results = false;
463 $leak_check = false;
464 $html_output = false;
465 $html_file = null;
466 $temp_source = null;
467 $temp_target = null;
468 $temp_urlbase = null;
469 $conf_passed = null;
470 $no_clean = false;
472 $cfgtypes = array('show', 'keep');
473 $cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp');
474 $cfg = array();
476 foreach($cfgtypes as $type) {
477 $cfg[$type] = array();
479 foreach($cfgfiles as $file) {
480 $cfg[$type][$file] = false;
484 if (getenv('TEST_PHP_ARGS')) {
486 if (!isset($argc) || !$argc || !isset($argv)) {
487 $argv = array(__FILE__);
490 $argv = array_merge($argv, explode(' ', getenv('TEST_PHP_ARGS')));
491 $argc = count($argv);
494 if (isset($argc) && $argc > 1) {
496 for ($i=1; $i<$argc; $i++) {
497 $is_switch = false;
498 $switch = substr($argv[$i],1,1);
499 $repeat = substr($argv[$i],0,1) == '-';
501 while ($repeat) {
503 if (!$is_switch) {
504 $switch = substr($argv[$i],1,1);
507 $is_switch = true;
509 if ($repeat) {
510 foreach($cfgtypes as $type) {
511 if (strpos($switch, '--' . $type) === 0) {
512 foreach($cfgfiles as $file) {
513 if ($switch == '--' . $type . '-' . $file) {
514 $cfg[$type][$file] = true;
515 $is_switch = false;
516 break;
523 if (!$is_switch) {
524 $is_switch = true;
525 break;
528 $repeat = false;
530 switch($switch) {
531 case 'r':
532 case 'l':
533 $test_list = file($argv[++$i]);
534 if ($test_list) {
535 foreach($test_list as $test) {
536 $matches = array();
537 if (preg_match('/^#.*\[(.*)\]\:\s+(.*)$/', $test, $matches)) {
538 $redir_tests[] = array($matches[1], $matches[2]);
539 } else if (strlen($test)) {
540 $test_files[] = trim($test);
544 if ($switch != 'l') {
545 break;
547 $i--;
548 // break left intentionally
549 case 'w':
550 $failed_tests_file = fopen($argv[++$i], 'w+t');
551 break;
552 case 'a':
553 $failed_tests_file = fopen($argv[++$i], 'a+t');
554 break;
555 case 'c':
556 $conf_passed = $argv[++$i];
557 break;
558 case 'd':
559 $ini_overwrites[] = $argv[++$i];
560 break;
561 case 'g':
562 $SHOW_ONLY_GROUPS = explode(",", $argv[++$i]);;
563 break;
564 //case 'h'
565 case '--keep-all':
566 foreach($cfgfiles as $file) {
567 $cfg['keep'][$file] = true;
569 break;
570 //case 'l'
571 case 'm':
572 $leak_check = true;
573 $valgrind_cmd = "valgrind --version";
574 $valgrind_header = system_with_timeout($valgrind_cmd, $environment);
575 $replace_count = 0;
576 if (!$valgrind_header) {
577 error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed.");
578 } else {
579 $valgrind_version = preg_replace("/valgrind-([0-9])\.([0-9])\.([0-9]+)([.-\w]+)?(\s+)/", '$1$2$3', $valgrind_header, 1, $replace_count);
580 if ($replace_count != 1 || !is_numeric($valgrind_version)) {
581 error("Valgrind returned invalid version info (\"$valgrind_header\"), cannot proceed.");
583 $valgrind_header = trim($valgrind_header);
585 break;
586 case 'n':
587 if (!$pass_option_n) {
588 $pass_options .= ' -n';
590 $pass_option_n = true;
591 break;
592 case '--no-clean':
593 $no_clean = true;
594 break;
595 case 'p':
596 $php = $argv[++$i];
597 putenv("TEST_PHP_EXECUTABLE=$php");
598 $environment['TEST_PHP_EXECUTABLE'] = $php;
599 break;
600 case 'q':
601 putenv('NO_INTERACTION=1');
602 break;
603 //case 'r'
604 case 's':
605 $output_file = $argv[++$i];
606 $just_save_results = true;
607 break;
608 case '--set-timeout':
609 $environment['TEST_TIMEOUT'] = $argv[++$i];
610 break;
611 case '--show-all':
612 foreach($cfgfiles as $file) {
613 $cfg['show'][$file] = true;
615 break;
616 case '--temp-source':
617 $temp_source = $argv[++$i];
618 break;
619 case '--temp-target':
620 $temp_target = $argv[++$i];
621 if ($temp_urlbase) {
622 $temp_urlbase = $temp_target;
624 break;
625 case '--temp-urlbase':
626 $temp_urlbase = $argv[++$i];
627 break;
628 case 'v':
629 case '--verbose':
630 $DETAILED = true;
631 break;
632 case 'x':
633 $environment['SKIP_SLOW_TESTS'] = 1;
634 break;
635 case '--offline':
636 $environment['SKIP_ONLINE_TESTS'] = 1;
637 break;
638 //case 'w'
639 case '-':
640 // repeat check with full switch
641 $switch = $argv[$i];
642 if ($switch != '-') {
643 $repeat = true;
645 break;
646 case '--html':
647 $html_file = fopen($argv[++$i], 'wt');
648 $html_output = is_resource($html_file);
649 break;
650 case '--version':
651 echo '$Id$' . "\n";
652 exit(1);
654 default:
655 echo "Illegal switch '$switch' specified!\n";
656 case 'h':
657 case '-help':
658 case '--help':
659 echo <<<HELP
660 Synopsis:
661 php run-tests.php [options] [files] [directories]
663 Options:
664 -l <file> Read the testfiles to be executed from <file>. After the test
665 has finished all failed tests are written to the same <file>.
666 If the list is empty and no further test is specified then
667 all tests are executed (same as: -r <file> -w <file>).
669 -r <file> Read the testfiles to be executed from <file>.
671 -w <file> Write a list of all failed tests to <file>.
673 -a <file> Same as -w but append rather then truncating <file>.
675 -c <file> Look for php.ini in directory <file> or use <file> as ini.
677 -n Pass -n option to the php binary (Do not use a php.ini).
679 -d foo=bar Pass -d option to the php binary (Define INI entry foo
680 with value 'bar').
682 -g Comma seperated list of groups to show during test run
683 (possible values: PASS, FAIL, XFAIL, SKIP, BORK, WARN, LEAK, REDIRECT).
685 -m Test for memory leaks with Valgrind.
687 -p <php> Specify PHP executable to run.
689 -q Quiet, no user interaction (same as environment NO_INTERACTION).
691 -s <file> Write output to <file>.
693 -x Sets 'SKIP_SLOW_TESTS' environmental variable.
695 --offline Sets 'SKIP_ONLINE_TESTS' environmental variable.
697 --verbose
698 -v Verbose mode.
700 --help
701 -h This Help.
703 --html <file> Generate HTML output.
705 --temp-source <sdir> --temp-target <tdir> [--temp-urlbase <url>]
706 Write temporary files to <tdir> by replacing <sdir> from the
707 filenames to generate with <tdir>. If --html is being used and
708 <url> given then the generated links are relative and prefixed
709 with the given url. In general you want to make <sdir> the path
710 to your source files and <tdir> some pach in your web page
711 hierarchy with <url> pointing to <tdir>.
713 --keep-[all|php|skip|clean]
714 Do not delete 'all' files, 'php' test file, 'skip' or 'clean'
715 file.
717 --set-timeout [n]
718 Set timeout for individual tests, where [n] is the number of
719 seconds. The default value is 60 seconds, or 300 seconds when
720 testing for memory leaks.
722 --show-[all|php|skip|clean|exp|diff|out]
723 Show 'all' files, 'php' test file, 'skip' or 'clean' file. You
724 can also use this to show the output 'out', the expected result
725 'exp' or the difference between them 'diff'. The result types
726 get written independent of the log format, however 'diff' only
727 exists when a test fails.
729 --no-clean Do not execute clean section if any.
731 HELP;
732 exit(1);
736 if (!$is_switch) {
737 $testfile = realpath($argv[$i]);
739 if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) {
741 if (preg_match("/\.phpt$/", $argv[$i])) {
742 $pattern_match = glob($argv[$i]);
743 } else if (preg_match("/\*$/", $argv[$i])) {
744 $pattern_match = glob($argv[$i] . '.phpt');
745 } else {
746 die("bogus test name " . $argv[$i] . "\n");
749 if (is_array($pattern_match)) {
750 $test_files = array_merge($test_files, $pattern_match);
753 } else if (is_dir($testfile)) {
754 find_files($testfile);
755 } else if (preg_match("/\.phpt$/", $testfile)) {
756 $test_files[] = $testfile;
757 } else {
758 die("bogus test name " . $argv[$i] . "\n");
763 if (strlen($conf_passed)) {
764 if (substr(PHP_OS, 0, 3) == "WIN") {
765 $pass_options .= " -c " . escapeshellarg($conf_passed);
766 } else {
767 $pass_options .= " -c '$conf_passed'";
771 $test_files = array_unique($test_files);
772 $test_files = array_merge($test_files, $redir_tests);
774 // Run selected tests.
775 $test_cnt = count($test_files);
777 if ($test_cnt) {
778 putenv('NO_INTERACTION=1');
779 verify_config();
780 write_information($html_output);
781 usort($test_files, "test_sort");
782 $start_time = time();
784 if (!$html_output) {
785 echo "Running selected tests.\n";
786 } else {
787 show_start($start_time);
790 $test_idx = 0;
791 run_all_tests($test_files, $environment);
792 $end_time = time();
794 if ($html_output) {
795 show_end($end_time);
798 if ($failed_tests_file) {
799 fclose($failed_tests_file);
802 if (count($test_files) || count($test_results)) {
803 compute_summary();
804 if ($html_output) {
805 fwrite($html_file, "<hr/>\n" . get_summary(false, true));
807 echo "=====================================================================";
808 echo get_summary(false, false);
811 if ($html_output) {
812 fclose($html_file);
815 if ($output_file != '' && $just_save_results) {
816 save_or_mail_results();
819 junit_save_xml();
821 if (getenv('REPORT_EXIT_STATUS') == 1 and preg_match('/FAILED(?: |$)/', implode(' ', $test_results))) {
822 exit(1);
825 exit(0);
829 verify_config();
830 write_information($html_output);
832 // Compile a list of all test files (*.phpt).
833 $test_files = array();
834 $exts_tested = count($exts_to_test);
835 $exts_skipped = 0;
836 $ignored_by_ext = 0;
837 sort($exts_to_test);
838 $test_dirs = array();
839 $optionals = array('tests', 'ext', 'Zend', 'ZendEngine2', 'sapi/cli', 'sapi/cgi');
841 foreach($optionals as $dir) {
842 if (@filetype($dir) == 'dir') {
843 $test_dirs[] = $dir;
847 // Convert extension names to lowercase
848 foreach ($exts_to_test as $key => $val) {
849 $exts_to_test[$key] = strtolower($val);
852 foreach ($test_dirs as $dir) {
853 find_files("{$cwd}/{$dir}", ($dir == 'ext'));
856 foreach ($user_tests as $dir) {
857 find_files($dir, ($dir == 'ext'));
860 function find_files($dir, $is_ext_dir = false, $ignore = false)
862 global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped, $exts_tested;
864 $o = opendir($dir) or error("cannot open directory: $dir");
866 while (($name = readdir($o)) !== false) {
868 if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', '.svn'))) {
869 $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test));
870 if ($skip_ext) {
871 $exts_skipped++;
873 find_files("{$dir}/{$name}", false, $ignore || $skip_ext);
876 // Cleanup any left-over tmp files from last run.
877 if (substr($name, -4) == '.tmp') {
878 @unlink("$dir/$name");
879 continue;
882 // Otherwise we're only interested in *.phpt files.
883 if (substr($name, -5) == '.phpt') {
884 if ($ignore) {
885 $ignored_by_ext++;
886 } else {
887 $testfile = realpath("{$dir}/{$name}");
888 $test_files[] = $testfile;
893 closedir($o);
896 function test_name($name)
898 if (is_array($name)) {
899 return $name[0] . ':' . $name[1];
900 } else {
901 return $name;
905 function test_sort($a, $b)
907 global $cwd;
909 $a = test_name($a);
910 $b = test_name($b);
912 $ta = strpos($a, "{$cwd}/tests") === 0 ? 1 + (strpos($a, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0;
913 $tb = strpos($b, "{$cwd}/tests") === 0 ? 1 + (strpos($b, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0;
915 if ($ta == $tb) {
916 return strcmp($a, $b);
917 } else {
918 return $tb - $ta;
922 $test_files = array_unique($test_files);
923 usort($test_files, "test_sort");
925 $start_time = time();
926 show_start($start_time);
928 $test_cnt = count($test_files);
929 $test_idx = 0;
930 run_all_tests($test_files, $environment);
931 $end_time = time();
933 if ($failed_tests_file) {
934 fclose($failed_tests_file);
937 // Summarize results
939 if (0 == count($test_results)) {
940 echo "No tests were run.\n";
941 return;
944 compute_summary();
946 show_end($end_time);
947 show_summary();
949 if ($html_output) {
950 fclose($html_file);
953 save_or_mail_results();
955 junit_save_xml();
957 if (getenv('REPORT_EXIT_STATUS') == 1 and $sum_results['FAILED']) {
958 exit(1);
960 exit(0);
963 // Send Email to QA Team
966 function mail_qa_team($data, $compression, $status = false)
968 $url_bits = parse_url(QA_SUBMISSION_PAGE);
970 if (($proxy = getenv('http_proxy'))) {
971 $proxy = parse_url($proxy);
972 $path = $url_bits['host'].$url_bits['path'];
973 $host = $proxy['host'];
974 if (empty($proxy['port'])) {
975 $proxy['port'] = 80;
977 $port = $proxy['port'];
978 } else {
979 $path = $url_bits['path'];
980 $host = $url_bits['host'];
981 $port = empty($url_bits['port']) ? 80 : $port = $url_bits['port'];
984 $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data)));
985 $data_length = strlen($data);
987 $fs = fsockopen($host, $port, $errno, $errstr, 10);
989 if (!$fs) {
990 return false;
993 $php_version = urlencode(TESTED_PHP_VERSION);
995 echo "\nPosting to ". QA_SUBMISSION_PAGE . "\n";
996 fwrite($fs, "POST " . $path . "?status=$status&version=$php_version HTTP/1.1\r\n");
997 fwrite($fs, "Host: " . $host . "\r\n");
998 fwrite($fs, "User-Agent: QA Browser 0.1\r\n");
999 fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n");
1000 fwrite($fs, "Content-Length: " . $data_length . "\r\n\r\n");
1001 fwrite($fs, $data);
1002 fwrite($fs, "\r\n\r\n");
1003 fclose($fs);
1005 return 1;
1010 // Write the given text to a temporary file, and return the filename.
1013 function save_text($filename, $text, $filename_copy = null)
1015 global $DETAILED;
1017 if ($filename_copy && $filename_copy != $filename) {
1018 if (file_put_contents($filename_copy, $text, FILE_BINARY) === false) {
1019 error("Cannot open file '" . $filename_copy . "' (save_text)");
1023 if (file_put_contents($filename, $text, FILE_BINARY) === false) {
1024 error("Cannot open file '" . $filename . "' (save_text)");
1027 if (1 < $DETAILED) echo "
1028 FILE $filename {{{
1029 $text
1035 // Write an error in a format recognizable to Emacs or MSVC.
1038 function error_report($testname, $logname, $tested)
1040 $testname = realpath($testname);
1041 $logname = realpath($logname);
1043 switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) {
1044 case 'MSVC':
1045 echo $testname . "(1) : $tested\n";
1046 echo $logname . "(1) : $tested\n";
1047 break;
1048 case 'EMACS':
1049 echo $testname . ":1: $tested\n";
1050 echo $logname . ":1: $tested\n";
1051 break;
1055 function system_with_timeout($commandline, $env = null, $stdin = null)
1057 global $leak_check, $cwd;
1059 $data = '';
1061 $bin_env = array();
1062 foreach((array)$env as $key => $value) {
1063 $bin_env[$key] = $value;
1066 $proc = proc_open($commandline, array(
1067 0 => array('pipe', 'r'),
1068 1 => array('pipe', 'w'),
1069 2 => array('pipe', 'w')
1070 ), $pipes, $cwd, $bin_env, array('suppress_errors' => true, 'binary_pipes' => true));
1072 if (!$proc) {
1073 return false;
1076 if (!is_null($stdin)) {
1077 fwrite($pipes[0], $stdin);
1079 fclose($pipes[0]);
1081 $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60);
1083 while (true) {
1084 /* hide errors from interrupted syscalls */
1085 $r = $pipes;
1086 $w = null;
1087 $e = null;
1089 $n = @stream_select($r, $w, $e, $timeout);
1091 if ($n === false) {
1092 break;
1093 } else if ($n === 0) {
1094 /* timed out */
1095 $data .= "\n ** ERROR: process timed out **\n";
1096 proc_terminate($proc, 9);
1097 return $data;
1098 } else if ($n > 0) {
1099 $line = fread($pipes[1], 8192);
1100 if (strlen($line) == 0) {
1101 /* EOF */
1102 break;
1104 $data .= $line;
1108 $stat = proc_get_status($proc);
1110 if ($stat['signaled']) {
1111 $data .= "\nTermsig=" . $stat['stopsig'];
1114 $code = proc_close($proc);
1115 return $data;
1118 function run_all_tests($test_files, $env, $redir_tested = null)
1120 global $test_results, $failed_tests_file, $php, $test_cnt, $test_idx;
1122 foreach($test_files as $name) {
1124 if (is_array($name)) {
1125 $index = "# $name[1]: $name[0]";
1127 if ($redir_tested) {
1128 $name = $name[0];
1130 } else if ($redir_tested) {
1131 $index = "# $redir_tested: $name";
1132 } else {
1133 $index = $name;
1135 $test_idx++;
1136 $result = run_test($php, $name, $env);
1138 if (!is_array($name) && $result != 'REDIR') {
1139 $test_results[$index] = $result;
1140 if ($failed_tests_file && ($result == 'XFAILED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) {
1141 fwrite($failed_tests_file, "$index\n");
1148 // Show file or result block
1150 function show_file_block($file, $block, $section = null)
1152 global $cfg;
1154 if ($cfg['show'][$file]) {
1156 if (is_null($section)) {
1157 $section = strtoupper($file);
1160 echo "\n========" . $section . "========\n";
1161 echo rtrim($block);
1162 echo "\n========DONE========\n";
1167 // Run an individual test case.
1169 function run_test($php, $file, $env)
1171 global $log_format, $info_params, $ini_overwrites, $cwd, $PHP_FAILED_TESTS;
1172 global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx;
1173 global $leak_check, $temp_source, $temp_target, $cfg, $environment;
1174 global $no_clean;
1175 global $valgrind_version;
1176 global $JUNIT;
1177 $temp_filenames = null;
1178 $org_file = $file;
1180 if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) {
1181 $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
1184 if (is_array($file)) {
1185 $file = $file[0];
1188 if ($DETAILED) echo "
1189 =================
1190 TEST $file
1193 // Load the sections of the test file.
1194 $section_text = array('TEST' => '');
1196 $fp = fopen($file, "rb") or error("Cannot open test file: $file");
1198 $borked = false;
1199 $bork_info = '';
1201 if (!feof($fp)) {
1202 $line = fgets($fp);
1204 if ($line === false) {
1205 $bork_info = "cannot read test";
1206 $borked = true;
1208 } else {
1209 $bork_info = "empty test [$file]";
1210 $borked = true;
1212 if (!$borked && strncmp('--TEST--', $line, 8)) {
1213 $bork_info = "tests must start with --TEST-- [$file]";
1214 $borked = true;
1217 $section = 'TEST';
1218 $secfile = false;
1219 $secdone = false;
1221 while (!feof($fp)) {
1222 $line = fgets($fp);
1224 if ($line === false) {
1225 break;
1228 // Match the beginning of a section.
1229 if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
1230 $section = $r[1];
1231 settype($section, 'string');
1233 if (isset($section_text[$section])) {
1234 $bork_info = "duplicated $section section";
1235 $borked = true;
1238 $section_text[$section] = '';
1239 $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL';
1240 $secdone = false;
1241 continue;
1244 // Add to the section text.
1245 if (!$secdone) {
1246 $section_text[$section] .= $line;
1249 // End of actual test?
1250 if ($secfile && preg_match('/^===DONE===\s*$/', $line)) {
1251 $secdone = true;
1255 // the redirect section allows a set of tests to be reused outside of
1256 // a given test dir
1257 if (!$borked) {
1258 if (@count($section_text['REDIRECTTEST']) == 1) {
1260 if ($IN_REDIRECT) {
1261 $borked = true;
1262 $bork_info = "Can't redirect a test from within a redirected test";
1263 } else {
1264 $borked = false;
1267 } else {
1269 if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) {
1270 $bork_info = "missing section --FILE--";
1271 $borked = true;
1274 if (@count($section_text['FILEEOF']) == 1) {
1275 $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']);
1276 unset($section_text['FILEEOF']);
1279 if (@count($section_text['FILE_EXTERNAL']) == 1) {
1280 // don't allow tests to retrieve files from anywhere but this subdirectory
1281 $section_text['FILE_EXTERNAL'] = dirname($file) . '/' . trim(str_replace('..', '', $section_text['FILE_EXTERNAL']));
1283 if (file_exists($section_text['FILE_EXTERNAL'])) {
1284 $section_text['FILE'] = file_get_contents($section_text['FILE_EXTERNAL'], FILE_BINARY);
1285 unset($section_text['FILE_EXTERNAL']);
1286 } else {
1287 $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']);
1288 $borked = true;
1292 if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) {
1293 $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
1294 $borked = true;
1298 fclose($fp);
1300 $shortname = str_replace($cwd . '/', '', $file);
1301 $tested_file = $shortname;
1303 if ($borked) {
1304 show_result("BORK", $bork_info, $tested_file);
1305 $PHP_FAILED_TESTS['BORKED'][] = array (
1306 'name' => $file,
1307 'test_name' => '',
1308 'output' => '',
1309 'diff' => '',
1310 'info' => "$bork_info [$file]",
1313 junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info);
1314 return 'BORKED';
1317 $tested = trim($section_text['TEST']);
1319 /* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */
1320 if (!empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['GZIP_POST']) || !empty($section_text['DEFLATE_POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['PUT']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) {
1321 if (isset($php_cgi)) {
1322 $old_php = $php;
1323 $php = $php_cgi . ' -C ';
1324 } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) {
1325 $old_php = $php;
1326 $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C ';
1327 } else {
1328 if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) {
1329 $old_php = $php;
1330 $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C ';
1331 } else if (file_exists("./sapi/cgi/php-cgi")) {
1332 $old_php = $php;
1333 $php = realpath("./sapi/cgi/php-cgi") . ' -C ';
1334 } else if (file_exists(dirname($php) . "/php-cgi")) {
1335 $old_php = $php;
1336 $php = realpath(dirname($php) . "/php-cgi") . ' -C ';
1337 } else {
1338 show_result('SKIP', $tested, $tested_file, "reason: CGI not available");
1340 junit_mark_test_as('SKIP', $shortname, $tested, 0, 'CGI not available');
1341 return 'SKIPPED';
1346 show_test($test_idx, $shortname);
1348 if (is_array($IN_REDIRECT)) {
1349 $temp_dir = $test_dir = $IN_REDIRECT['dir'];
1350 } else {
1351 $temp_dir = $test_dir = realpath(dirname($file));
1354 if ($temp_source && $temp_target) {
1355 $temp_dir = str_replace($temp_source, $temp_target, $temp_dir);
1358 $main_file_name = basename($file,'phpt');
1360 $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff';
1361 $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log';
1362 $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp';
1363 $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out';
1364 $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem';
1365 $sh_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'sh';
1366 $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
1367 $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
1368 $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
1369 $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
1370 $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
1371 $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
1372 $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.');
1373 $tmp_relative_file = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $test_file) . 't';
1375 if ($temp_source && $temp_target) {
1376 $temp_skipif .= 's';
1377 $temp_file .= 's';
1378 $temp_clean .= 's';
1379 $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps';
1381 if (!is_dir(dirname($copy_file))) {
1382 mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file));
1385 if (isset($section_text['FILE'])) {
1386 save_text($copy_file, $section_text['FILE']);
1389 $temp_filenames = array(
1390 'file' => $copy_file,
1391 'diff' => $diff_filename,
1392 'log' => $log_filename,
1393 'exp' => $exp_filename,
1394 'out' => $output_filename,
1395 'mem' => $memcheck_filename,
1396 'sh' => $sh_filename,
1397 'php' => $temp_file,
1398 'skip' => $temp_skipif,
1399 'clean'=> $temp_clean);
1402 if (is_array($IN_REDIRECT)) {
1403 $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']);
1404 $tested_file = $tmp_relative_file;
1407 // unlink old test results
1408 @unlink($diff_filename);
1409 @unlink($log_filename);
1410 @unlink($exp_filename);
1411 @unlink($output_filename);
1412 @unlink($memcheck_filename);
1413 @unlink($sh_filename);
1414 @unlink($temp_file);
1415 @unlink($test_file);
1416 @unlink($temp_skipif);
1417 @unlink($test_skipif);
1418 @unlink($tmp_post);
1419 @unlink($temp_clean);
1420 @unlink($test_clean);
1422 // Reset environment from any previous test.
1423 $env['REDIRECT_STATUS'] = '';
1424 $env['QUERY_STRING'] = '';
1425 $env['PATH_TRANSLATED'] = '';
1426 $env['SCRIPT_FILENAME'] = '';
1427 $env['REQUEST_METHOD'] = '';
1428 $env['CONTENT_TYPE'] = '';
1429 $env['CONTENT_LENGTH'] = '';
1430 $env['TZ'] = '';
1432 if (!empty($section_text['ENV'])) {
1434 foreach(explode("\n", trim($section_text['ENV'])) as $e) {
1435 $e = explode('=', trim($e), 2);
1437 if (!empty($e[0]) && isset($e[1])) {
1438 $env[$e[0]] = $e[1];
1443 // Default ini settings
1444 $ini_settings = array();
1445 // additional ini overwrites
1446 //$ini_overwrites[] = 'setting=value';
1447 settings2array($ini_overwrites, $ini_settings);
1449 // Any special ini settings
1450 // these may overwrite the test defaults...
1451 if (array_key_exists('INI', $section_text)) {
1452 if (strpos($section_text['INI'], '{PWD}') !== false) {
1453 $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
1455 settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings);
1458 // Additional required extensions
1459 if (array_key_exists('EXTENSIONS', $section_text)) {
1460 $ext_dir=`$php -r 'echo ini_get("extension_dir");'`;
1461 $extensions = preg_split("/[\n\r]+/", trim($section_text['EXTENSIONS']));
1462 $loaded = explode(",", `$php -n -r 'echo join(",", get_loaded_extensions());'`);
1463 foreach ($extensions as $req_ext) {
1464 if (!in_array($req_ext, $loaded)) {
1465 $ini_settings['extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $req_ext . '.' . PHP_SHLIB_SUFFIX;
1470 settings2params($ini_settings);
1472 // Check if test should be skipped.
1473 $info = '';
1474 $warn = false;
1476 if (array_key_exists('SKIPIF', $section_text)) {
1478 if (trim($section_text['SKIPIF'])) {
1479 show_file_block('skip', $section_text['SKIPIF']);
1480 save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif);
1481 $extra = substr(PHP_OS, 0, 3) !== "WIN" ?
1482 "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
1484 if ($leak_check) {
1485 $env['USE_ZEND_ALLOC'] = '0';
1486 $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
1487 } else {
1488 $env['USE_ZEND_ALLOC'] = '1';
1489 $env['ZEND_DONT_UNLOAD_MODULES'] = 0;
1492 junit_start_timer($shortname);
1494 $output = system_with_timeout("$extra $php $pass_options -q $ini_settings -d display_errors=0 \"$test_skipif\"", $env);
1496 junit_finish_timer($shortname);
1498 if (!$cfg['keep']['skip']) {
1499 @unlink($test_skipif);
1502 if (!strncasecmp('skip', ltrim($output), 4)) {
1504 if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) {
1505 show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames);
1506 } else {
1507 show_result('SKIP', $tested, $tested_file, '', $temp_filenames);
1510 if (isset($old_php)) {
1511 $php = $old_php;
1514 if (!$cfg['keep']['skip']) {
1515 @unlink($test_skipif);
1518 $message = !empty($m[1]) ? $m[1] : '';
1519 junit_mark_test_as('SKIP', $shortname, $tested, null, "<![CDATA[\n$message\n]]>");
1520 return 'SKIPPED';
1523 if (!strncasecmp('info', ltrim($output), 4)) {
1524 if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) {
1525 $info = " (info: $m[1])";
1529 if (!strncasecmp('warn', ltrim($output), 4)) {
1530 if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) {
1531 $warn = true; /* only if there is a reason */
1532 $info = " (warn: $m[1])";
1538 if (@count($section_text['REDIRECTTEST']) == 1) {
1539 $test_files = array();
1541 $IN_REDIRECT = eval($section_text['REDIRECTTEST']);
1542 $IN_REDIRECT['via'] = "via [$shortname]\n\t";
1543 $IN_REDIRECT['dir'] = realpath(dirname($file));
1544 $IN_REDIRECT['prefix'] = trim($section_text['TEST']);
1546 if (count($IN_REDIRECT['TESTS']) == 1) {
1548 if (is_array($org_file)) {
1549 $test_files[] = $org_file[1];
1550 } else {
1551 $GLOBALS['test_files'] = $test_files;
1552 find_files($IN_REDIRECT['TESTS']);
1554 foreach($GLOBALS['test_files'] as $f) {
1555 $test_files[] = array($f, $file);
1558 $test_cnt += @count($test_files) - 1;
1559 $test_idx--;
1561 show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file);
1563 // set up environment
1564 $redirenv = array_merge($environment, $IN_REDIRECT['ENV']);
1565 $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR;
1567 usort($test_files, "test_sort");
1568 run_all_tests($test_files, $redirenv, $tested);
1570 show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file);
1572 // a redirected test never fails
1573 $IN_REDIRECT = false;
1575 junit_mark_test_as('PASS', $shortname, $tested);
1576 return 'REDIR';
1578 } else {
1580 $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory.";
1581 show_result("BORK", $bork_info, '', $temp_filenames);
1582 $PHP_FAILED_TESTS['BORKED'][] = array (
1583 'name' => $file,
1584 'test_name' => '',
1585 'output' => '',
1586 'diff' => '',
1587 'info' => "$bork_info [$file]",
1592 if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) {
1594 if (is_array($org_file)) {
1595 $file = $org_file[0];
1598 $bork_info = "Redirected test did not contain redirection info";
1599 show_result("BORK", $bork_info, '', $temp_filenames);
1600 $PHP_FAILED_TESTS['BORKED'][] = array (
1601 'name' => $file,
1602 'test_name' => '',
1603 'output' => '',
1604 'diff' => '',
1605 'info' => "$bork_info [$file]",
1608 junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info);
1610 return 'BORKED';
1613 // We've satisfied the preconditions - run the test!
1614 show_file_block('php', $section_text['FILE'], 'TEST');
1615 save_text($test_file, $section_text['FILE'], $temp_file);
1617 if (array_key_exists('GET', $section_text)) {
1618 $query_string = trim($section_text['GET']);
1619 } else {
1620 $query_string = '';
1623 $env['REDIRECT_STATUS'] = '1';
1624 $env['QUERY_STRING'] = $query_string;
1625 $env['PATH_TRANSLATED'] = $test_file;
1626 $env['SCRIPT_FILENAME'] = $test_file;
1628 if (array_key_exists('COOKIE', $section_text)) {
1629 $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
1630 } else {
1631 $env['HTTP_COOKIE'] = '';
1634 $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : '';
1636 if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
1638 $post = trim($section_text['POST_RAW']);
1639 $raw_lines = explode("\n", $post);
1641 $request = '';
1642 $started = false;
1644 foreach ($raw_lines as $line) {
1646 if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
1647 $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
1648 continue;
1651 if ($started) {
1652 $request .= "\n";
1655 $started = true;
1656 $request .= $line;
1659 $env['CONTENT_LENGTH'] = strlen($request);
1660 $env['REQUEST_METHOD'] = 'POST';
1662 if (empty($request)) {
1663 junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request');
1664 return 'BORKED';
1667 save_text($tmp_post, $request);
1668 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1670 } elseif (array_key_exists('PUT', $section_text) && !empty($section_text['PUT'])) {
1672 $post = trim($section_text['PUT']);
1673 $raw_lines = explode("\n", $post);
1675 $request = '';
1676 $started = false;
1678 foreach ($raw_lines as $line) {
1680 if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
1681 $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
1682 continue;
1685 if ($started) {
1686 $request .= "\n";
1689 $started = true;
1690 $request .= $line;
1693 $env['CONTENT_LENGTH'] = strlen($request);
1694 $env['REQUEST_METHOD'] = 'PUT';
1696 if (empty($request)) {
1697 junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request');
1698 return 'BORKED';
1701 save_text($tmp_post, $request);
1702 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1704 } else if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
1706 $post = trim($section_text['POST']);
1707 save_text($tmp_post, $post);
1708 $content_length = strlen($post);
1710 $env['REQUEST_METHOD'] = 'POST';
1711 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1712 $env['CONTENT_LENGTH'] = $content_length;
1714 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1716 } else if (array_key_exists('GZIP_POST', $section_text) && !empty($section_text['GZIP_POST'])) {
1718 $post = trim($section_text['GZIP_POST']);
1719 $post = gzencode($post, 9, FORCE_GZIP);
1720 $env['HTTP_CONTENT_ENCODING'] = 'gzip';
1722 save_text($tmp_post, $post);
1723 $content_length = strlen($post);
1725 $env['REQUEST_METHOD'] = 'POST';
1726 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1727 $env['CONTENT_LENGTH'] = $content_length;
1729 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1731 } else if (array_key_exists('DEFLATE_POST', $section_text) && !empty($section_text['DEFLATE_POST'])) {
1732 $post = trim($section_text['DEFLATE_POST']);
1733 $post = gzcompress($post, 9);
1734 $env['HTTP_CONTENT_ENCODING'] = 'deflate';
1735 save_text($tmp_post, $post);
1736 $content_length = strlen($post);
1738 $env['REQUEST_METHOD'] = 'POST';
1739 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1740 $env['CONTENT_LENGTH'] = $content_length;
1742 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1745 } else {
1747 $env['REQUEST_METHOD'] = 'GET';
1748 $env['CONTENT_TYPE'] = '';
1749 $env['CONTENT_LENGTH'] = '';
1751 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" $args 2>&1";
1754 if ($leak_check) {
1755 $env['USE_ZEND_ALLOC'] = '0';
1756 $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
1758 if ($valgrind_version >= 330) {
1759 /* valgrind 3.3.0+ doesn't have --log-file-exactly option */
1760 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file=$memcheck_filename $cmd";
1761 } else {
1762 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd";
1765 } else {
1766 $env['USE_ZEND_ALLOC'] = '1';
1767 $env['ZEND_DONT_UNLOAD_MODULES'] = 0;
1770 if ($DETAILED) echo "
1771 CONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . "
1772 CONTENT_TYPE = " . $env['CONTENT_TYPE'] . "
1773 PATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . "
1774 QUERY_STRING = " . $env['QUERY_STRING'] . "
1775 REDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . "
1776 REQUEST_METHOD = " . $env['REQUEST_METHOD'] . "
1777 SCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . "
1778 HTTP_COOKIE = " . $env['HTTP_COOKIE'] . "
1779 COMMAND $cmd
1782 junit_start_timer($shortname);
1784 $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null);
1786 junit_finish_timer($shortname);
1788 if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) {
1790 if (trim($section_text['CLEAN'])) {
1791 show_file_block('clean', $section_text['CLEAN']);
1792 save_text($test_clean, trim($section_text['CLEAN']), $temp_clean);
1794 if (!$no_clean) {
1795 $clean_params = array();
1796 settings2array($ini_overwrites, $clean_params);
1797 settings2params($clean_params);
1798 $extra = substr(PHP_OS, 0, 3) !== "WIN" ?
1799 "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
1800 system_with_timeout("$extra $php $pass_options -q $clean_params \"$test_clean\"", $env);
1803 if (!$cfg['keep']['clean']) {
1804 @unlink($test_clean);
1809 @unlink($tmp_post);
1811 $leaked = false;
1812 $passed = false;
1814 if ($leak_check) { // leak check
1815 $leaked = filesize($memcheck_filename) > 0;
1817 if (!$leaked) {
1818 @unlink($memcheck_filename);
1822 // Does the output match what is expected?
1823 $output = preg_replace("/\r\n/", "\n", trim($out));
1825 /* when using CGI, strip the headers from the output */
1826 $headers = "";
1828 if (isset($old_php) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
1829 $output = trim($match[2]);
1830 $rh = preg_split("/[\n\r]+/", $match[1]);
1831 $headers = array();
1833 foreach ($rh as $line) {
1834 if (strpos($line, ':') !== false) {
1835 $line = explode(':', $line, 2);
1836 $headers[trim($line[0])] = trim($line[1]);
1841 $failed_headers = false;
1843 if (isset($section_text['EXPECTHEADERS'])) {
1844 $want = array();
1845 $wanted_headers = array();
1846 $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']);
1848 foreach($lines as $line) {
1849 if (strpos($line, ':') !== false) {
1850 $line = explode(':', $line, 2);
1851 $want[trim($line[0])] = trim($line[1]);
1852 $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]);
1856 $org_headers = $headers;
1857 $headers = array();
1858 $output_headers = array();
1860 foreach($want as $k => $v) {
1862 if (isset($org_headers[$k])) {
1863 $headers = $org_headers[$k];
1864 $output_headers[] = $k . ': ' . $org_headers[$k];
1867 if (!isset($org_headers[$k]) || $org_headers[$k] != $v) {
1868 $failed_headers = true;
1872 ksort($wanted_headers);
1873 $wanted_headers = join("\n", $wanted_headers);
1874 ksort($output_headers);
1875 $output_headers = join("\n", $output_headers);
1878 show_file_block('out', $output);
1880 if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
1882 if (isset($section_text['EXPECTF'])) {
1883 $wanted = trim($section_text['EXPECTF']);
1884 } else {
1885 $wanted = trim($section_text['EXPECTREGEX']);
1888 show_file_block('exp', $wanted);
1889 $wanted_re = preg_replace('/\r\n/', "\n", $wanted);
1891 if (isset($section_text['EXPECTF'])) {
1893 // do preg_quote, but miss out any %r delimited sections
1894 $temp = "";
1895 $r = "%r";
1896 $startOffset = 0;
1897 $length = strlen($wanted_re);
1898 while($startOffset < $length) {
1899 $start = strpos($wanted_re, $r, $startOffset);
1900 if ($start !== false) {
1901 // we have found a start tag
1902 $end = strpos($wanted_re, $r, $start+2);
1903 if ($end === false) {
1904 // unbalanced tag, ignore it.
1905 $end = $start = $length;
1907 } else {
1908 // no more %r sections
1909 $start = $end = $length;
1911 // quote a non re portion of the string
1912 $temp = $temp . preg_quote(substr($wanted_re, $startOffset, ($start - $startOffset)), '/');
1913 // add the re unquoted.
1914 if ($end > $start) {
1915 $temp = $temp . '(' . substr($wanted_re, $start+2, ($end - $start-2)). ')';
1917 $startOffset = $end + 2;
1919 $wanted_re = $temp;
1921 $wanted_re = str_replace(
1922 array('%binary_string_optional%'),
1923 'string',
1924 $wanted_re
1926 $wanted_re = str_replace(
1927 array('%unicode_string_optional%'),
1928 'string',
1929 $wanted_re
1931 $wanted_re = str_replace(
1932 array('%unicode\|string%', '%string\|unicode%'),
1933 'string',
1934 $wanted_re
1936 $wanted_re = str_replace(
1937 array('%u\|b%', '%b\|u%'),
1939 $wanted_re
1941 // Stick to basics
1942 $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re);
1943 $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re);
1944 $wanted_re = str_replace('%S', '[^\r\n]*', $wanted_re);
1945 $wanted_re = str_replace('%a', '.+', $wanted_re);
1946 $wanted_re = str_replace('%A', '.*', $wanted_re);
1947 $wanted_re = str_replace('%w', '\s*', $wanted_re);
1948 $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re);
1949 $wanted_re = str_replace('%d', '\d+', $wanted_re);
1950 $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re);
1951 $wanted_re = str_replace('%f', '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', $wanted_re);
1952 $wanted_re = str_replace('%c', '.', $wanted_re);
1953 // %f allows two points "-.0.0" but that is the best *simple* expression
1955 /* DEBUG YOUR REGEX HERE
1956 var_dump($wanted_re);
1957 print(str_repeat('=', 80) . "\n");
1958 var_dump($output);
1960 if (preg_match("/^$wanted_re\$/s", $output)) {
1961 $passed = true;
1962 if (!$cfg['keep']['php']) {
1963 @unlink($test_file);
1965 if (isset($old_php)) {
1966 $php = $old_php;
1969 if (!$leaked && !$failed_headers) {
1970 if (isset($section_text['XFAIL'] )) {
1971 $warn = true;
1972 $info = " (warn: XFAIL section but test passes)";
1973 }else {
1974 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
1975 junit_mark_test_as('PASS', $shortname, $tested);
1976 return 'PASSED';
1981 } else {
1983 $wanted = trim($section_text['EXPECT']);
1984 $wanted = preg_replace('/\r\n/',"\n", $wanted);
1985 show_file_block('exp', $wanted);
1987 // compare and leave on success
1988 if (!strcmp($output, $wanted)) {
1989 $passed = true;
1991 if (!$cfg['keep']['php']) {
1992 @unlink($test_file);
1995 if (isset($old_php)) {
1996 $php = $old_php;
1999 if (!$leaked && !$failed_headers) {
2000 if (isset($section_text['XFAIL'] )) {
2001 $warn = true;
2002 $info = " (warn: XFAIL section but test passes)";
2003 }else {
2004 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
2005 junit_mark_test_as('PASS', $shortname, $tested);
2006 return 'PASSED';
2011 $wanted_re = null;
2014 // Test failed so we need to report details.
2015 if ($failed_headers) {
2016 $passed = false;
2017 $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted;
2018 $output = $output_headers . "\n--HEADERS--\n" . $output;
2020 if (isset($wanted_re)) {
2021 $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re;
2025 if ($leaked) {
2026 $restype[] = 'LEAK';
2029 if ($warn) {
2030 $restype[] = 'WARN';
2033 if (!$passed) {
2034 if (isset($section_text['XFAIL'])) {
2035 $restype[] = 'XFAIL';
2036 $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']);
2037 } else {
2038 $restype[] = 'FAIL';
2042 if (!$passed) {
2044 // write .exp
2045 if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, $wanted, FILE_BINARY) === false) {
2046 error("Cannot create expected test output - $exp_filename");
2049 // write .out
2050 if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) {
2051 error("Cannot create test output - $output_filename");
2054 // write .diff
2055 $diff = generate_diff($wanted, $wanted_re, $output);
2056 if (is_array($IN_REDIRECT)) {
2057 $diff = "# original source file: $shortname\n" . $diff;
2059 show_file_block('diff', $diff);
2060 if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, $diff, FILE_BINARY) === false) {
2061 error("Cannot create test diff - $diff_filename");
2064 // write .sh
2065 if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh
2067 {$cmd}
2068 ", FILE_BINARY) === false) {
2069 error("Cannot create test shell script - $sh_filename");
2071 chmod($sh_filename, 0755);
2073 // write .log
2074 if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, "
2075 ---- EXPECTED OUTPUT
2076 $wanted
2077 ---- ACTUAL OUTPUT
2078 $output
2079 ---- FAILED
2080 ", FILE_BINARY) === false) {
2081 error("Cannot create test log - $log_filename");
2082 error_report($file, $log_filename, $tested);
2086 show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames);
2088 foreach ($restype as $type) {
2089 $PHP_FAILED_TESTS[$type.'ED'][] = array (
2090 'name' => $file,
2091 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]",
2092 'output' => $output_filename,
2093 'diff' => $diff_filename,
2094 'info' => $info,
2098 if (isset($old_php)) {
2099 $php = $old_php;
2102 $diff = empty($diff) ? '' : "<![CDATA[\n " . preg_replace('/\e/', '<esc>', $diff) . "\n]]>";
2104 junit_mark_test_as($restype, str_replace($cwd . '/', '', $tested_file), $tested, null, $info, $diff);
2106 return $restype[0] . 'ED';
2109 function comp_line($l1, $l2, $is_reg)
2111 if ($is_reg) {
2112 return preg_match('/^'. $l1 . '$/s', $l2);
2113 } else {
2114 return !strcmp($l1, $l2);
2118 function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps)
2120 $equal = 0;
2122 while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
2123 $idx1++;
2124 $idx2++;
2125 $equal++;
2126 $steps--;
2128 if (--$steps > 0) {
2129 $eq1 = 0;
2130 $st = $steps / 2;
2132 for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) {
2133 $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st);
2135 if ($eq > $eq1) {
2136 $eq1 = $eq;
2140 $eq2 = 0;
2141 $st = $steps;
2143 for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) {
2144 $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st);
2145 if ($eq > $eq2) {
2146 $eq2 = $eq;
2150 if ($eq1 > $eq2) {
2151 $equal += $eq1;
2152 } else if ($eq2 > 0) {
2153 $equal += $eq2;
2157 return $equal;
2160 function generate_array_diff($ar1, $ar2, $is_reg, $w)
2162 $idx1 = 0; $ofs1 = 0; $cnt1 = @count($ar1);
2163 $idx2 = 0; $ofs2 = 0; $cnt2 = @count($ar2);
2164 $diff = array();
2165 $old1 = array();
2166 $old2 = array();
2168 while ($idx1 < $cnt1 && $idx2 < $cnt2) {
2170 if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
2171 $idx1++;
2172 $idx2++;
2173 continue;
2174 } else {
2176 $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1+1, $idx2, $cnt1, $cnt2, 10);
2177 $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2+1, $cnt1, $cnt2, 10);
2179 if ($c1 > $c2) {
2180 $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++];
2181 $last = 1;
2182 } else if ($c2 > 0) {
2183 $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++];
2184 $last = 2;
2185 } else {
2186 $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++];
2187 $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++];
2192 reset($old1); $k1 = key($old1); $l1 = -2;
2193 reset($old2); $k2 = key($old2); $l2 = -2;
2195 while ($k1 !== null || $k2 !== null) {
2197 if ($k1 == $l1 + 1 || $k2 === null) {
2198 $l1 = $k1;
2199 $diff[] = current($old1);
2200 $k1 = next($old1) ? key($old1) : null;
2201 } else if ($k2 == $l2 + 1 || $k1 === null) {
2202 $l2 = $k2;
2203 $diff[] = current($old2);
2204 $k2 = next($old2) ? key($old2) : null;
2205 } else if ($k1 < $k2) {
2206 $l1 = $k1;
2207 $diff[] = current($old1);
2208 $k1 = next($old1) ? key($old1) : null;
2209 } else {
2210 $l2 = $k2;
2211 $diff[] = current($old2);
2212 $k2 = next($old2) ? key($old2) : null;
2216 while ($idx1 < $cnt1) {
2217 $diff[] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++];
2220 while ($idx2 < $cnt2) {
2221 $diff[] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++];
2224 return $diff;
2227 function generate_diff($wanted, $wanted_re, $output)
2229 $w = explode("\n", $wanted);
2230 $o = explode("\n", $output);
2231 $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re);
2232 $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w);
2234 return implode("\r\n", $diff);
2237 function error($message)
2239 echo "ERROR: {$message}\n";
2240 exit(1);
2243 function settings2array($settings, &$ini_settings)
2245 foreach($settings as $setting) {
2247 if (strpos($setting, '=') !== false) {
2248 $setting = explode("=", $setting, 2);
2249 $name = trim($setting[0]);
2250 $value = trim($setting[1]);
2252 if ($name == 'extension') {
2254 if (!isset($ini_settings[$name])) {
2255 $ini_settings[$name] = array();
2258 $ini_settings[$name][] = $value;
2260 } else {
2261 $ini_settings[$name] = $value;
2267 function settings2params(&$ini_settings)
2269 $settings = '';
2271 foreach($ini_settings as $name => $value) {
2273 if (is_array($value)) {
2274 foreach($value as $val) {
2275 $val = addslashes($val);
2276 $settings .= " -d \"$name=$val\"";
2278 } else {
2279 if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value{0} == '"') {
2280 $len = strlen($value);
2282 if ($value{$len - 1} == '"') {
2283 $value{0} = "'";
2284 $value{$len - 1} = "'";
2286 } else {
2287 $value = addslashes($value);
2290 $settings .= " -d \"$name=$value\"";
2294 $ini_settings = $settings;
2297 function compute_summary()
2299 global $n_total, $test_results, $ignored_by_ext, $sum_results, $percent_results;
2301 $n_total = count($test_results);
2302 $n_total += $ignored_by_ext;
2303 $sum_results = array(
2304 'PASSED' => 0,
2305 'WARNED' => 0,
2306 'SKIPPED' => 0,
2307 'FAILED' => 0,
2308 'BORKED' => 0,
2309 'LEAKED' => 0,
2310 'XFAILED' => 0
2313 foreach ($test_results as $v) {
2314 $sum_results[$v]++;
2317 $sum_results['SKIPPED'] += $ignored_by_ext;
2318 $percent_results = array();
2320 while (list($v, $n) = each($sum_results)) {
2321 $percent_results[$v] = (100.0 * $n) / $n_total;
2325 function get_summary($show_ext_summary, $show_html)
2327 global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $leak_check;
2329 $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED'];
2331 if ($x_total) {
2332 $x_warned = (100.0 * $sum_results['WARNED']) / $x_total;
2333 $x_failed = (100.0 * $sum_results['FAILED']) / $x_total;
2334 $x_xfailed = (100.0 * $sum_results['XFAILED']) / $x_total;
2335 $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total;
2336 $x_passed = (100.0 * $sum_results['PASSED']) / $x_total;
2337 } else {
2338 $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = 0;
2341 $summary = '';
2343 if ($show_html) {
2344 $summary .= "<pre>\n";
2347 if ($show_ext_summary) {
2348 $summary .= '
2349 =====================================================================
2350 TEST RESULT SUMMARY
2351 ---------------------------------------------------------------------
2352 Exts skipped : ' . sprintf('%4d', $exts_skipped) . '
2353 Exts tested : ' . sprintf('%4d', $exts_tested) . '
2354 ---------------------------------------------------------------------
2358 $summary .= '
2359 Number of tests : ' . sprintf('%4d', $n_total) . ' ' . sprintf('%8d', $x_total);
2361 if ($sum_results['BORKED']) {
2362 $summary .= '
2363 Tests borked : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------';
2366 $summary .= '
2367 Tests skipped : ' . sprintf('%4d (%5.1f%%)', $sum_results['SKIPPED'], $percent_results['SKIPPED']) . ' --------
2368 Tests warned : ' . sprintf('%4d (%5.1f%%)', $sum_results['WARNED'], $percent_results['WARNED']) . ' ' . sprintf('(%5.1f%%)', $x_warned) . '
2369 Tests failed : ' . sprintf('%4d (%5.1f%%)', $sum_results['FAILED'], $percent_results['FAILED']) . ' ' . sprintf('(%5.1f%%)', $x_failed) . '
2370 Expected fail : ' . sprintf('%4d (%5.1f%%)', $sum_results['XFAILED'], $percent_results['XFAILED']) . ' ' . sprintf('(%5.1f%%)', $x_xfailed);
2372 if ($leak_check) {
2373 $summary .= '
2374 Tests leaked : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked);
2377 $summary .= '
2378 Tests passed : ' . sprintf('%4d (%5.1f%%)', $sum_results['PASSED'], $percent_results['PASSED']) . ' ' . sprintf('(%5.1f%%)', $x_passed) . '
2379 ---------------------------------------------------------------------
2380 Time taken : ' . sprintf('%4d seconds', $end_time - $start_time) . '
2381 =====================================================================
2383 $failed_test_summary = '';
2385 if (count($PHP_FAILED_TESTS['XFAILED'])) {
2386 $failed_test_summary .= '
2387 =====================================================================
2388 EXPECTED FAILED TEST SUMMARY
2389 ---------------------------------------------------------------------
2391 foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) {
2392 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
2394 $failed_test_summary .= "=====================================================================\n";
2397 if (count($PHP_FAILED_TESTS['BORKED'])) {
2398 $failed_test_summary .= '
2399 =====================================================================
2400 BORKED TEST SUMMARY
2401 ---------------------------------------------------------------------
2403 foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) {
2404 $failed_test_summary .= $failed_test_data['info'] . "\n";
2407 $failed_test_summary .= "=====================================================================\n";
2410 if (count($PHP_FAILED_TESTS['FAILED'])) {
2411 $failed_test_summary .= '
2412 =====================================================================
2413 FAILED TEST SUMMARY
2414 ---------------------------------------------------------------------
2416 foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) {
2417 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
2419 $failed_test_summary .= "=====================================================================\n";
2421 if (count($PHP_FAILED_TESTS['WARNED'])) {
2422 $failed_test_summary .= '
2423 =====================================================================
2424 WARNED TEST SUMMARY
2425 ---------------------------------------------------------------------
2427 foreach ($PHP_FAILED_TESTS['WARNED'] as $failed_test_data) {
2428 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
2431 $failed_test_summary .= "=====================================================================\n";
2434 if (count($PHP_FAILED_TESTS['LEAKED'])) {
2435 $failed_test_summary .= '
2436 =====================================================================
2437 LEAKED TEST SUMMARY
2438 ---------------------------------------------------------------------
2440 foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) {
2441 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
2444 $failed_test_summary .= "=====================================================================\n";
2447 if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) {
2448 $summary .= $failed_test_summary;
2451 if ($show_html) {
2452 $summary .= "</pre>";
2455 return $summary;
2458 function show_start($start_time)
2460 global $html_output, $html_file;
2462 if ($html_output) {
2463 fwrite($html_file, "<h2>Time Start: " . date('Y-m-d H:i:s', $start_time) . "</h2>\n");
2464 fwrite($html_file, "<table>\n");
2467 echo "TIME START " . date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n";
2470 function show_end($end_time)
2472 global $html_output, $html_file;
2474 if ($html_output) {
2475 fwrite($html_file, "</table>\n");
2476 fwrite($html_file, "<h2>Time End: " . date('Y-m-d H:i:s', $end_time) . "</h2>\n");
2479 echo "=====================================================================\nTIME END " . date('Y-m-d H:i:s', $end_time) . "\n";
2482 function show_summary()
2484 global $html_output, $html_file;
2486 if ($html_output) {
2487 fwrite($html_file, "<hr/>\n" . get_summary(true, true));
2490 echo get_summary(true, false);
2493 function show_redirect_start($tests, $tested, $tested_file)
2495 global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS;
2497 if ($html_output) {
2498 fwrite($html_file, "<tr><td colspan='3'>---&gt; $tests ($tested [$tested_file]) begin</td></tr>\n");
2501 if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) {
2502 echo "REDIRECT $tests ($tested [$tested_file]) begin\n";
2503 } else {
2504 // Write over the last line to avoid random trailing chars on next echo
2505 echo str_repeat(" ", $line_length), "\r";
2509 function show_redirect_ends($tests, $tested, $tested_file)
2511 global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS;
2513 if ($html_output) {
2514 fwrite($html_file, "<tr><td colspan='3'>---&gt; $tests ($tested [$tested_file]) done</td></tr>\n");
2517 if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) {
2518 echo "REDIRECT $tests ($tested [$tested_file]) done\n";
2519 } else {
2520 // Write over the last line to avoid random trailing chars on next echo
2521 echo str_repeat(" ", $line_length), "\r";
2525 function show_test($test_idx, $shortname)
2527 global $test_cnt;
2528 global $line_length;
2530 $str = "TEST $test_idx/$test_cnt [$shortname]\r";
2531 $line_length = strlen($str);
2532 echo $str;
2533 flush();
2536 function show_result($result, $tested, $tested_file, $extra = '', $temp_filenames = null)
2538 global $html_output, $html_file, $temp_target, $temp_urlbase, $line_length, $SHOW_ONLY_GROUPS;
2540 if (!$SHOW_ONLY_GROUPS || in_array($result, $SHOW_ONLY_GROUPS)) {
2541 echo "$result $tested [$tested_file] $extra\n";
2542 } else {
2543 // Write over the last line to avoid random trailing chars on next echo
2544 echo str_repeat(" ", $line_length), "\r";
2547 if ($html_output) {
2549 if (isset($temp_filenames['file']) && file_exists($temp_filenames['file'])) {
2550 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']);
2551 $tested = "<a href='$url'>$tested</a>";
2554 if (isset($temp_filenames['skip']) && file_exists($temp_filenames['skip'])) {
2556 if (empty($extra)) {
2557 $extra = "skipif";
2560 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']);
2561 $extra = "<a href='$url'>$extra</a>";
2563 } else if (empty($extra)) {
2564 $extra = "&nbsp;";
2567 if (isset($temp_filenames['diff']) && file_exists($temp_filenames['diff'])) {
2568 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']);
2569 $diff = "<a href='$url'>diff</a>";
2570 } else {
2571 $diff = "&nbsp;";
2574 if (isset($temp_filenames['mem']) && file_exists($temp_filenames['mem'])) {
2575 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']);
2576 $mem = "<a href='$url'>leaks</a>";
2577 } else {
2578 $mem = "&nbsp;";
2581 fwrite($html_file,
2582 "<tr>" .
2583 "<td>$result</td>" .
2584 "<td>$tested</td>" .
2585 "<td>$extra</td>" .
2586 "<td>$diff</td>" .
2587 "<td>$mem</td>" .
2588 "</tr>\n");
2592 function junit_init() {
2593 // Check whether a junit log is wanted.
2594 $JUNIT = getenv('TEST_PHP_JUNIT');
2595 if (empty($JUNIT)) {
2596 $JUNIT = FALSE;
2597 } elseif (!$fp = fopen($JUNIT, 'w')) {
2598 error("Failed to open $JUNIT for writing.");
2599 } else {
2600 $JUNIT = array(
2601 'fp' => $fp,
2602 'name' => 'php-src',
2603 'test_total' => 0,
2604 'test_pass' => 0,
2605 'test_fail' => 0,
2606 'test_error' => 0,
2607 'test_skip' => 0,
2608 'execution_time'=> 0,
2609 'suites' => array(),
2610 'files' => array()
2614 $GLOBALS['JUNIT'] = $JUNIT;
2617 function junit_save_xml() {
2618 global $JUNIT;
2619 if (!junit_enabled()) return;
2621 $xml = '<?xml version="1.0" encoding="UTF-8"?>'. PHP_EOL .
2622 '<testsuites>' . PHP_EOL;
2623 $xml .= junit_get_suite_xml();
2624 $xml .= '</testsuites>';
2625 fwrite($JUNIT['fp'], $xml);
2628 function junit_get_suite_xml($suite_name = '') {
2629 global $JUNIT;
2631 $suite = $suite_name ? $JUNIT['suites'][$suite_name] : $JUNIT;
2633 $result = sprintf(
2634 '<testsuite name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL,
2635 $suite['name'], $suite['test_total'], $suite['test_fail'], $suite['test_error'], $suite['test_skip'],
2636 $suite['execution_time']
2639 foreach($suite['suites'] as $sub_suite) {
2640 $result .= junit_get_suite_xml($sub_suite['name']);
2643 // Output files only in subsuites
2644 if (!empty($suite_name)) {
2645 foreach($suite['files'] as $file) {
2646 $result .= $JUNIT['files'][$file]['xml'];
2650 $result .= '</testsuite>' . PHP_EOL;
2652 return $result;
2655 function junit_enabled() {
2656 global $JUNIT;
2657 return !empty($JUNIT);
2661 * @param array|string $type
2662 * @param string $file_name
2663 * @param string $test_name
2664 * @param int|string $time
2665 * @param string $message
2666 * @param string $details
2667 * @return void
2669 function junit_mark_test_as($type, $file_name, $test_name, $time = null, $message = '', $details = '') {
2670 global $JUNIT;
2671 if (!junit_enabled()) return;
2673 $suite = junit_get_suitename_for($file_name);
2675 junit_suite_record($suite, 'test_total');
2677 $time = null !== $time ? $time : junit_get_timer($file_name);
2678 junit_suite_record($suite, 'execution_time', $time);
2680 $escaped_details = htmlspecialchars($details, ENT_QUOTES, 'UTF-8');
2682 $escaped_test_name = basename($file_name) . ' - ' . htmlspecialchars($test_name, ENT_QUOTES);
2683 $JUNIT['files'][$file_name]['xml'] = "<testcase classname='$suite' name='$escaped_test_name' time='$time'>\n";
2685 if (is_array($type)) {
2686 $output_type = $type[0] . 'ED';
2687 $temp = array_intersect(array('XFAIL', 'FAIL'), $type);
2688 $type = reset($temp);
2689 } else {
2690 $output_type = $type . 'ED';
2693 if ('PASS' == $type || 'XFAIL' == $type) {
2694 junit_suite_record($suite, 'test_pass');
2695 } elseif ('BORK' == $type) {
2696 junit_suite_record($suite, 'test_error');
2697 $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$message'/>\n";
2698 } elseif ('SKIP' == $type) {
2699 junit_suite_record($suite, 'test_skip');
2700 $JUNIT['files'][$file_name]['xml'] .= "<skipped>$message</skipped>\n";
2701 } elseif('FAIL' == $type) {
2702 junit_suite_record($suite, 'test_fail');
2703 $JUNIT['files'][$file_name]['xml'] .= "<failure type='$output_type' message='$message'>$escaped_details</failure>\n";
2704 } else {
2705 junit_suite_record($suite, 'test_error');
2706 $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$message'>$escaped_details</error>\n";
2709 $JUNIT['files'][$file_name]['xml'] .= "</testcase>\n";
2713 function junit_suite_record($suite, $param, $value = 1) {
2714 global $JUNIT;
2716 $JUNIT[$param] += $value;
2717 $JUNIT['suites'][$suite][$param] += $value;
2720 function junit_get_timer($file_name) {
2721 global $JUNIT;
2722 if (!junit_enabled()) return 0;
2724 if (isset($JUNIT['files'][$file_name]['total'])) {
2725 return number_format($JUNIT['files'][$file_name]['total'], 4);
2728 return 0;
2731 function junit_start_timer($file_name) {
2732 global $JUNIT;
2733 if (!junit_enabled()) return;
2735 if (!isset($JUNIT['files'][$file_name]['start'])) {
2736 $JUNIT['files'][$file_name]['start'] = microtime(true);
2738 $suite = junit_get_suitename_for($file_name);
2739 junit_init_suite($suite);
2740 $JUNIT['suites'][$suite]['files'][$file_name] = $file_name;
2744 function junit_get_suitename_for($file_name) {
2745 return junit_path_to_classname(dirname($file_name));
2748 function junit_path_to_classname($file_name) {
2749 global $JUNIT;
2750 return $JUNIT['name'] . '.' . str_replace(DIRECTORY_SEPARATOR, '.', $file_name);
2753 function junit_init_suite($suite_name) {
2754 global $JUNIT;
2755 if (!junit_enabled()) return;
2757 if (!empty($JUNIT['suites'][$suite_name])) {
2758 return;
2761 $JUNIT['suites'][$suite_name] = array(
2762 'name' => $suite_name,
2763 'test_total' => 0,
2764 'test_pass' => 0,
2765 'test_fail' => 0,
2766 'test_error' => 0,
2767 'test_skip' => 0,
2768 'suites' => array(),
2769 'files' => array(),
2770 'execution_time'=> 0,
2774 function junit_finish_timer($file_name) {
2775 global $JUNIT;
2776 if (!junit_enabled()) return;
2778 if (!isset($JUNIT['files'][$file_name]['start'])) {
2779 error("Timer for $file_name was not started!");
2782 if (!isset($JUNIT['files'][$file_name]['total'])) {
2783 $JUNIT['files'][$file_name]['total'] = 0;
2786 $start = $JUNIT['files'][$file_name]['start'];
2787 $JUNIT['files'][$file_name]['total'] += microtime(true) - $start;
2788 unset($JUNIT['files'][$file_name]['start']);
2792 * Local variables:
2793 * tab-width: 4
2794 * c-basic-offset: 4
2795 * End:
2796 * vim: noet sw=4 ts=4