fix php compilation when mysql is enabled
[tomato.git] / release / src / router / php / ext / mysqlnd / run-tests.php
blob08df7ca7091cd20b83b280b30409067c860ec956
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',
243 'log_errors_max_len=0',
246 function write_information($show_html)
248 global $cwd, $php, $php_cgi, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $leak_check, $valgrind_header;
250 // Get info from php
251 $info_file = __DIR__ . '/run-test-info.php';
252 @unlink($info_file);
253 $php_info = '<?php echo "
254 PHP_SAPI : " , PHP_SAPI , "
255 PHP_VERSION : " , phpversion() , "
256 ZEND_VERSION: " , zend_version() , "
257 PHP_OS : " , PHP_OS , " - " , php_uname() , "
258 INI actual : " , realpath(get_cfg_var("cfg_file_path")) , "
259 More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n","", php_ini_scanned_files()) : "** not determined **"); ?>';
260 save_text($info_file, $php_info);
261 $info_params = array();
262 settings2array($ini_overwrites, $info_params);
263 settings2params($info_params);
264 $php_info = `$php $pass_options $info_params "$info_file"`;
265 define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`);
267 if ($php_cgi && $php != $php_cgi) {
268 $php_info_cgi = `$php_cgi $pass_options $info_params -q "$info_file"`;
269 $php_info_sep = "\n---------------------------------------------------------------------";
270 $php_cgi_info = "$php_info_sep\nPHP : $php_cgi $php_info_cgi$php_info_sep";
271 } else {
272 $php_cgi_info = '';
275 @unlink($info_file);
277 // load list of enabled extensions
278 save_text($info_file, '<?php echo join(",", get_loaded_extensions()); ?>');
279 $exts_to_test = explode(',',`$php $pass_options $info_params "$info_file"`);
280 // check for extensions that need special handling and regenerate
281 $info_params_ex = array(
282 'session' => array('session.auto_start=0'),
283 'tidy' => array('tidy.clean_output=0'),
284 'zlib' => array('zlib.output_compression=Off'),
285 'xdebug' => array('xdebug.default_enable=0'),
286 'mbstring' => array('mbstring.func_overload=0'),
289 foreach($info_params_ex as $ext => $ini_overwrites_ex) {
290 if (in_array($ext, $exts_to_test)) {
291 $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex);
295 @unlink($info_file);
297 // Write test context information.
298 echo "
299 =====================================================================
300 PHP : $php $php_info $php_cgi_info
301 CWD : $cwd
302 Extra dirs : ";
303 foreach ($user_tests as $test_dir) {
304 echo "{$test_dir}\n ";
306 echo "
307 VALGRIND : " . ($leak_check ? $valgrind_header : 'Not used') . "
308 =====================================================================
312 define('PHP_QA_EMAIL', 'qa-reports@lists.php.net');
313 define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php');
314 define('QA_REPORTS_PAGE', 'http://qa.php.net/reports');
316 function save_or_mail_results()
318 global $sum_results, $just_save_results, $failed_test_summary,
319 $PHP_FAILED_TESTS, $CUR_DIR, $php, $output_file, $compression;
321 /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */
322 if (!getenv('NO_INTERACTION')) {
323 $fp = fopen("php://stdin", "r+");
324 if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED'] || $sum_results['XFAILED']) {
325 echo "\nYou may have found a problem in PHP.";
327 echo "\nThis report can be automatically sent to the PHP QA team at\n";
328 echo QA_REPORTS_PAGE . " and http://news.php.net/php.qa.reports\n";
329 echo "This gives us a better understanding of PHP's behavior.\n";
330 echo "If you don't want to send the report immediately you can choose\n";
331 echo "option \"s\" to save it. You can then email it to ". PHP_QA_EMAIL . " later.\n";
332 echo "Do you want to send this report now? [Yns]: ";
333 flush();
335 $user_input = fgets($fp, 10);
336 $just_save_results = (strtolower($user_input[0]) == 's');
339 if ($just_save_results || !getenv('NO_INTERACTION')) {
340 if ($just_save_results || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') {
342 * Collect information about the host system for our report
343 * Fetch phpinfo() output so that we can see the PHP enviroment
344 * Make an archive of all the failed tests
345 * Send an email
347 if ($just_save_results) {
348 $user_input = 's';
351 /* Ask the user to provide an email address, so that QA team can contact the user */
352 if (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) {
353 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): ";
354 flush();
355 $user_email = trim(fgets($fp, 1024));
356 $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email));
359 $failed_tests_data = '';
360 $sep = "\n" . str_repeat('=', 80) . "\n";
361 $failed_tests_data .= $failed_test_summary . "\n";
362 $failed_tests_data .= get_summary(true, false) . "\n";
364 if ($sum_results['FAILED']) {
365 foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) {
366 $failed_tests_data .= $sep . $test_info['name'] . $test_info['info'];
367 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output']), FILE_BINARY);
368 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff']), FILE_BINARY);
369 $failed_tests_data .= $sep . "\n\n";
371 $status = "failed";
372 } else {
373 $status = "success";
376 $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep;
377 $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n";
378 $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A';
380 if (substr(PHP_OS, 0, 3) != "WIN") {
381 /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */
382 if (getenv('PHP_AUTOCONF')) {
383 $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version');
384 } else {
385 $autoconf = shell_exec('autoconf --version');
388 /* Always use the generated libtool - Mac OSX uses 'glibtool' */
389 $libtool = shell_exec($CUR_DIR . '/libtool --version');
391 /* Use shtool to find out if there is glibtool present (MacOSX) */
392 $sys_libtool_path = shell_exec(__DIR__ . '/build/shtool path glibtool libtool');
394 if ($sys_libtool_path) {
395 $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version');
398 /* Try the most common flags for 'version' */
399 $flags = array('-v', '-V', '--version');
400 $cc_status = 0;
402 foreach($flags AS $flag) {
403 system(getenv('CC') . " $flag >/dev/null 2>&1", $cc_status);
404 if ($cc_status == 0) {
405 $compiler = shell_exec(getenv('CC') . " $flag 2>&1");
406 break;
410 $ldd = shell_exec("ldd $php 2>/dev/null");
413 $failed_tests_data .= "Autoconf:\n$autoconf\n";
414 $failed_tests_data .= "Bundled Libtool:\n$libtool\n";
415 $failed_tests_data .= "System Libtool:\n$sys_libtool\n";
416 $failed_tests_data .= "Compiler:\n$compiler\n";
417 $failed_tests_data .= "Bison:\n". shell_exec('bison --version 2>/dev/null') . "\n";
418 $failed_tests_data .= "Libraries:\n$ldd\n";
419 $failed_tests_data .= "\n";
421 if (isset($user_email)) {
422 $failed_tests_data .= "User's E-mail: " . $user_email . "\n\n";
425 $failed_tests_data .= $sep . "PHPINFO" . $sep;
426 $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null');
428 if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status)) {
429 file_put_contents($output_file, $failed_tests_data);
431 if (!$just_save_results) {
432 echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n";
435 echo "Please send " . $output_file . " to " . PHP_QA_EMAIL . " manually, thank you.\n";
436 } else {
437 fwrite($fp, "\nThank you for helping to make PHP better.\n");
438 fclose($fp);
444 // Determine the tests to be run.
446 $test_files = array();
447 $redir_tests = array();
448 $test_results = array();
449 $PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array(), 'XFAILED' => array());
451 // If parameters given assume they represent selected tests to run.
452 $failed_tests_file= false;
453 $pass_option_n = false;
454 $pass_options = '';
456 $compression = 0;
457 $output_file = $CUR_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt';
459 if ($compression && in_array("compress.zlib", stream_get_filters())) {
460 $output_file = 'compress.zlib://' . $output_file . '.gz';
463 $just_save_results = false;
464 $leak_check = false;
465 $html_output = false;
466 $html_file = null;
467 $temp_source = null;
468 $temp_target = null;
469 $temp_urlbase = null;
470 $conf_passed = null;
471 $no_clean = false;
473 $cfgtypes = array('show', 'keep');
474 $cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp');
475 $cfg = array();
477 foreach($cfgtypes as $type) {
478 $cfg[$type] = array();
480 foreach($cfgfiles as $file) {
481 $cfg[$type][$file] = false;
485 if (getenv('TEST_PHP_ARGS')) {
487 if (!isset($argc) || !$argc || !isset($argv)) {
488 $argv = array(__FILE__);
491 $argv = array_merge($argv, explode(' ', getenv('TEST_PHP_ARGS')));
492 $argc = count($argv);
495 if (isset($argc) && $argc > 1) {
497 for ($i=1; $i<$argc; $i++) {
498 $is_switch = false;
499 $switch = substr($argv[$i],1,1);
500 $repeat = substr($argv[$i],0,1) == '-';
502 while ($repeat) {
504 if (!$is_switch) {
505 $switch = substr($argv[$i],1,1);
508 $is_switch = true;
510 if ($repeat) {
511 foreach($cfgtypes as $type) {
512 if (strpos($switch, '--' . $type) === 0) {
513 foreach($cfgfiles as $file) {
514 if ($switch == '--' . $type . '-' . $file) {
515 $cfg[$type][$file] = true;
516 $is_switch = false;
517 break;
524 if (!$is_switch) {
525 $is_switch = true;
526 break;
529 $repeat = false;
531 switch($switch) {
532 case 'r':
533 case 'l':
534 $test_list = file($argv[++$i]);
535 if ($test_list) {
536 foreach($test_list as $test) {
537 $matches = array();
538 if (preg_match('/^#.*\[(.*)\]\:\s+(.*)$/', $test, $matches)) {
539 $redir_tests[] = array($matches[1], $matches[2]);
540 } else if (strlen($test)) {
541 $test_files[] = trim($test);
545 if ($switch != 'l') {
546 break;
548 $i--;
549 // break left intentionally
550 case 'w':
551 $failed_tests_file = fopen($argv[++$i], 'w+t');
552 break;
553 case 'a':
554 $failed_tests_file = fopen($argv[++$i], 'a+t');
555 break;
556 case 'c':
557 $conf_passed = $argv[++$i];
558 break;
559 case 'd':
560 $ini_overwrites[] = $argv[++$i];
561 break;
562 case 'g':
563 $SHOW_ONLY_GROUPS = explode(",", $argv[++$i]);;
564 break;
565 //case 'h'
566 case '--keep-all':
567 foreach($cfgfiles as $file) {
568 $cfg['keep'][$file] = true;
570 break;
571 //case 'l'
572 case 'm':
573 $leak_check = true;
574 $valgrind_cmd = "valgrind --version";
575 $valgrind_header = system_with_timeout($valgrind_cmd, $environment);
576 $replace_count = 0;
577 if (!$valgrind_header) {
578 error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed.");
579 } else {
580 $valgrind_version = preg_replace("/valgrind-(\d+)\.(\d+)\.(\d+)([.\w_-]+)?(\s+)/", '$1.$2.$3', $valgrind_header, 1, $replace_count);
581 if ($replace_count != 1) {
582 error("Valgrind returned invalid version info (\"$valgrind_header\"), cannot proceed.");
584 $valgrind_header = trim($valgrind_header);
586 break;
587 case 'n':
588 if (!$pass_option_n) {
589 $pass_options .= ' -n';
591 $pass_option_n = true;
592 break;
593 case '--no-clean':
594 $no_clean = true;
595 break;
596 case 'p':
597 $php = $argv[++$i];
598 putenv("TEST_PHP_EXECUTABLE=$php");
599 $environment['TEST_PHP_EXECUTABLE'] = $php;
600 break;
601 case 'P':
602 if(constant('PHP_BINARY')) {
603 $php = PHP_BINARY;
604 } else {
605 break;
607 putenv("TEST_PHP_EXECUTABLE=$php");
608 $environment['TEST_PHP_EXECUTABLE'] = $php;
609 break;
610 case 'q':
611 putenv('NO_INTERACTION=1');
612 break;
613 //case 'r'
614 case 's':
615 $output_file = $argv[++$i];
616 $just_save_results = true;
617 break;
618 case '--set-timeout':
619 $environment['TEST_TIMEOUT'] = $argv[++$i];
620 break;
621 case '--show-all':
622 foreach($cfgfiles as $file) {
623 $cfg['show'][$file] = true;
625 break;
626 case '--temp-source':
627 $temp_source = $argv[++$i];
628 break;
629 case '--temp-target':
630 $temp_target = $argv[++$i];
631 if ($temp_urlbase) {
632 $temp_urlbase = $temp_target;
634 break;
635 case '--temp-urlbase':
636 $temp_urlbase = $argv[++$i];
637 break;
638 case 'v':
639 case '--verbose':
640 $DETAILED = true;
641 break;
642 case 'x':
643 $environment['SKIP_SLOW_TESTS'] = 1;
644 break;
645 case '--offline':
646 $environment['SKIP_ONLINE_TESTS'] = 1;
647 break;
648 //case 'w'
649 case '-':
650 // repeat check with full switch
651 $switch = $argv[$i];
652 if ($switch != '-') {
653 $repeat = true;
655 break;
656 case '--html':
657 $html_file = fopen($argv[++$i], 'wt');
658 $html_output = is_resource($html_file);
659 break;
660 case '--version':
661 echo '$Id$' . "\n";
662 exit(1);
664 default:
665 echo "Illegal switch '$switch' specified!\n";
666 case 'h':
667 case '-help':
668 case '--help':
669 echo <<<HELP
670 Synopsis:
671 php run-tests.php [options] [files] [directories]
673 Options:
674 -l <file> Read the testfiles to be executed from <file>. After the test
675 has finished all failed tests are written to the same <file>.
676 If the list is empty and no further test is specified then
677 all tests are executed (same as: -r <file> -w <file>).
679 -r <file> Read the testfiles to be executed from <file>.
681 -w <file> Write a list of all failed tests to <file>.
683 -a <file> Same as -w but append rather then truncating <file>.
685 -c <file> Look for php.ini in directory <file> or use <file> as ini.
687 -n Pass -n option to the php binary (Do not use a php.ini).
689 -d foo=bar Pass -d option to the php binary (Define INI entry foo
690 with value 'bar').
692 -g Comma separated list of groups to show during test run
693 (possible values: PASS, FAIL, XFAIL, SKIP, BORK, WARN, LEAK, REDIRECT).
695 -m Test for memory leaks with Valgrind.
697 -p <php> Specify PHP executable to run.
699 -P Use PHP_BINARY as PHP executable to run.
701 -q Quiet, no user interaction (same as environment NO_INTERACTION).
703 -s <file> Write output to <file>.
705 -x Sets 'SKIP_SLOW_TESTS' environmental variable.
707 --offline Sets 'SKIP_ONLINE_TESTS' environmental variable.
709 --verbose
710 -v Verbose mode.
712 --help
713 -h This Help.
715 --html <file> Generate HTML output.
717 --temp-source <sdir> --temp-target <tdir> [--temp-urlbase <url>]
718 Write temporary files to <tdir> by replacing <sdir> from the
719 filenames to generate with <tdir>. If --html is being used and
720 <url> given then the generated links are relative and prefixed
721 with the given url. In general you want to make <sdir> the path
722 to your source files and <tdir> some pach in your web page
723 hierarchy with <url> pointing to <tdir>.
725 --keep-[all|php|skip|clean]
726 Do not delete 'all' files, 'php' test file, 'skip' or 'clean'
727 file.
729 --set-timeout [n]
730 Set timeout for individual tests, where [n] is the number of
731 seconds. The default value is 60 seconds, or 300 seconds when
732 testing for memory leaks.
734 --show-[all|php|skip|clean|exp|diff|out]
735 Show 'all' files, 'php' test file, 'skip' or 'clean' file. You
736 can also use this to show the output 'out', the expected result
737 'exp' or the difference between them 'diff'. The result types
738 get written independent of the log format, however 'diff' only
739 exists when a test fails.
741 --no-clean Do not execute clean section if any.
743 HELP;
744 exit(1);
748 if (!$is_switch) {
749 $testfile = realpath($argv[$i]);
751 if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) {
753 if (preg_match("/\.phpt$/", $argv[$i])) {
754 $pattern_match = glob($argv[$i]);
755 } else if (preg_match("/\*$/", $argv[$i])) {
756 $pattern_match = glob($argv[$i] . '.phpt');
757 } else {
758 die("bogus test name " . $argv[$i] . "\n");
761 if (is_array($pattern_match)) {
762 $test_files = array_merge($test_files, $pattern_match);
765 } else if (is_dir($testfile)) {
766 find_files($testfile);
767 } else if (preg_match("/\.phpt$/", $testfile)) {
768 $test_files[] = $testfile;
769 } else {
770 die("bogus test name " . $argv[$i] . "\n");
775 if (strlen($conf_passed)) {
776 if (substr(PHP_OS, 0, 3) == "WIN") {
777 $pass_options .= " -c " . escapeshellarg($conf_passed);
778 } else {
779 $pass_options .= " -c '$conf_passed'";
783 $test_files = array_unique($test_files);
784 $test_files = array_merge($test_files, $redir_tests);
786 // Run selected tests.
787 $test_cnt = count($test_files);
789 if ($test_cnt) {
790 putenv('NO_INTERACTION=1');
791 verify_config();
792 write_information($html_output);
793 usort($test_files, "test_sort");
794 $start_time = time();
796 if (!$html_output) {
797 echo "Running selected tests.\n";
798 } else {
799 show_start($start_time);
802 $test_idx = 0;
803 run_all_tests($test_files, $environment);
804 $end_time = time();
806 if ($html_output) {
807 show_end($end_time);
810 if ($failed_tests_file) {
811 fclose($failed_tests_file);
814 if (count($test_files) || count($test_results)) {
815 compute_summary();
816 if ($html_output) {
817 fwrite($html_file, "<hr/>\n" . get_summary(false, true));
819 echo "=====================================================================";
820 echo get_summary(false, false);
823 if ($html_output) {
824 fclose($html_file);
827 if ($output_file != '' && $just_save_results) {
828 save_or_mail_results();
831 junit_save_xml();
833 if (getenv('REPORT_EXIT_STATUS') == 1 and preg_match('/FAILED(?: |$)/', implode(' ', $test_results))) {
834 exit(1);
837 exit(0);
841 verify_config();
842 write_information($html_output);
844 // Compile a list of all test files (*.phpt).
845 $test_files = array();
846 $exts_tested = count($exts_to_test);
847 $exts_skipped = 0;
848 $ignored_by_ext = 0;
849 sort($exts_to_test);
850 $test_dirs = array();
851 $optionals = array('tests', 'ext', 'Zend', 'ZendEngine2', 'sapi/cli', 'sapi/cgi');
853 foreach($optionals as $dir) {
854 if (@filetype($dir) == 'dir') {
855 $test_dirs[] = $dir;
859 // Convert extension names to lowercase
860 foreach ($exts_to_test as $key => $val) {
861 $exts_to_test[$key] = strtolower($val);
864 foreach ($test_dirs as $dir) {
865 find_files("{$cwd}/{$dir}", ($dir == 'ext'));
868 foreach ($user_tests as $dir) {
869 find_files($dir, ($dir == 'ext'));
872 function find_files($dir, $is_ext_dir = false, $ignore = false)
874 global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped, $exts_tested;
876 $o = opendir($dir) or error("cannot open directory: $dir");
878 while (($name = readdir($o)) !== false) {
880 if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', '.svn'))) {
881 $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test));
882 if ($skip_ext) {
883 $exts_skipped++;
885 find_files("{$dir}/{$name}", false, $ignore || $skip_ext);
888 // Cleanup any left-over tmp files from last run.
889 if (substr($name, -4) == '.tmp') {
890 @unlink("$dir/$name");
891 continue;
894 // Otherwise we're only interested in *.phpt files.
895 if (substr($name, -5) == '.phpt') {
896 if ($ignore) {
897 $ignored_by_ext++;
898 } else {
899 $testfile = realpath("{$dir}/{$name}");
900 $test_files[] = $testfile;
905 closedir($o);
908 function test_name($name)
910 if (is_array($name)) {
911 return $name[0] . ':' . $name[1];
912 } else {
913 return $name;
917 function test_sort($a, $b)
919 global $cwd;
921 $a = test_name($a);
922 $b = test_name($b);
924 $ta = strpos($a, "{$cwd}/tests") === 0 ? 1 + (strpos($a, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0;
925 $tb = strpos($b, "{$cwd}/tests") === 0 ? 1 + (strpos($b, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0;
927 if ($ta == $tb) {
928 return strcmp($a, $b);
929 } else {
930 return $tb - $ta;
934 $test_files = array_unique($test_files);
935 usort($test_files, "test_sort");
937 $start_time = time();
938 show_start($start_time);
940 $test_cnt = count($test_files);
941 $test_idx = 0;
942 run_all_tests($test_files, $environment);
943 $end_time = time();
945 if ($failed_tests_file) {
946 fclose($failed_tests_file);
949 // Summarize results
951 if (0 == count($test_results)) {
952 echo "No tests were run.\n";
953 return;
956 compute_summary();
958 show_end($end_time);
959 show_summary();
961 if ($html_output) {
962 fclose($html_file);
965 save_or_mail_results();
967 junit_save_xml();
969 if (getenv('REPORT_EXIT_STATUS') == 1 and $sum_results['FAILED']) {
970 exit(1);
972 exit(0);
975 // Send Email to QA Team
978 function mail_qa_team($data, $compression, $status = false)
980 $url_bits = parse_url(QA_SUBMISSION_PAGE);
982 if (($proxy = getenv('http_proxy'))) {
983 $proxy = parse_url($proxy);
984 $path = $url_bits['host'].$url_bits['path'];
985 $host = $proxy['host'];
986 if (empty($proxy['port'])) {
987 $proxy['port'] = 80;
989 $port = $proxy['port'];
990 } else {
991 $path = $url_bits['path'];
992 $host = $url_bits['host'];
993 $port = empty($url_bits['port']) ? 80 : $port = $url_bits['port'];
996 $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data)));
997 $data_length = strlen($data);
999 $fs = fsockopen($host, $port, $errno, $errstr, 10);
1001 if (!$fs) {
1002 return false;
1005 $php_version = urlencode(TESTED_PHP_VERSION);
1007 echo "\nPosting to ". QA_SUBMISSION_PAGE . "\n";
1008 fwrite($fs, "POST " . $path . "?status=$status&version=$php_version HTTP/1.1\r\n");
1009 fwrite($fs, "Host: " . $host . "\r\n");
1010 fwrite($fs, "User-Agent: QA Browser 0.1\r\n");
1011 fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n");
1012 fwrite($fs, "Content-Length: " . $data_length . "\r\n\r\n");
1013 fwrite($fs, $data);
1014 fwrite($fs, "\r\n\r\n");
1015 fclose($fs);
1017 return 1;
1022 // Write the given text to a temporary file, and return the filename.
1025 function save_text($filename, $text, $filename_copy = null)
1027 global $DETAILED;
1029 if ($filename_copy && $filename_copy != $filename) {
1030 if (file_put_contents($filename_copy, $text, FILE_BINARY) === false) {
1031 error("Cannot open file '" . $filename_copy . "' (save_text)");
1035 if (file_put_contents($filename, $text, FILE_BINARY) === false) {
1036 error("Cannot open file '" . $filename . "' (save_text)");
1039 if (1 < $DETAILED) echo "
1040 FILE $filename {{{
1041 $text
1047 // Write an error in a format recognizable to Emacs or MSVC.
1050 function error_report($testname, $logname, $tested)
1052 $testname = realpath($testname);
1053 $logname = realpath($logname);
1055 switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) {
1056 case 'MSVC':
1057 echo $testname . "(1) : $tested\n";
1058 echo $logname . "(1) : $tested\n";
1059 break;
1060 case 'EMACS':
1061 echo $testname . ":1: $tested\n";
1062 echo $logname . ":1: $tested\n";
1063 break;
1067 function system_with_timeout($commandline, $env = null, $stdin = null)
1069 global $leak_check, $cwd;
1071 $data = '';
1073 $bin_env = array();
1074 foreach((array)$env as $key => $value) {
1075 $bin_env[$key] = $value;
1078 $proc = proc_open($commandline, array(
1079 0 => array('pipe', 'r'),
1080 1 => array('pipe', 'w'),
1081 2 => array('pipe', 'w')
1082 ), $pipes, $cwd, $bin_env, array('suppress_errors' => true, 'binary_pipes' => true));
1084 if (!$proc) {
1085 return false;
1088 if (!is_null($stdin)) {
1089 fwrite($pipes[0], $stdin);
1091 fclose($pipes[0]);
1092 unset($pipes[0]);
1094 $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60);
1096 while (true) {
1097 /* hide errors from interrupted syscalls */
1098 $r = $pipes;
1099 $w = null;
1100 $e = null;
1102 $n = @stream_select($r, $w, $e, $timeout);
1104 if ($n === false) {
1105 break;
1106 } else if ($n === 0) {
1107 /* timed out */
1108 $data .= "\n ** ERROR: process timed out **\n";
1109 proc_terminate($proc, 9);
1110 return $data;
1111 } else if ($n > 0) {
1112 $line = fread($pipes[1], 8192);
1113 if (strlen($line) == 0) {
1114 /* EOF */
1115 break;
1117 $data .= $line;
1121 $stat = proc_get_status($proc);
1123 if ($stat['signaled']) {
1124 $data .= "\nTermsig=" . $stat['stopsig'];
1127 $code = proc_close($proc);
1128 return $data;
1131 function run_all_tests($test_files, $env, $redir_tested = null)
1133 global $test_results, $failed_tests_file, $php, $test_cnt, $test_idx;
1135 foreach($test_files as $name) {
1137 if (is_array($name)) {
1138 $index = "# $name[1]: $name[0]";
1140 if ($redir_tested) {
1141 $name = $name[0];
1143 } else if ($redir_tested) {
1144 $index = "# $redir_tested: $name";
1145 } else {
1146 $index = $name;
1148 $test_idx++;
1149 $result = run_test($php, $name, $env);
1151 if (!is_array($name) && $result != 'REDIR') {
1152 $test_results[$index] = $result;
1153 if ($failed_tests_file && ($result == 'XFAILED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) {
1154 fwrite($failed_tests_file, "$index\n");
1161 // Show file or result block
1163 function show_file_block($file, $block, $section = null)
1165 global $cfg;
1167 if ($cfg['show'][$file]) {
1169 if (is_null($section)) {
1170 $section = strtoupper($file);
1173 echo "\n========" . $section . "========\n";
1174 echo rtrim($block);
1175 echo "\n========DONE========\n";
1180 // Run an individual test case.
1182 function run_test($php, $file, $env)
1184 global $log_format, $info_params, $ini_overwrites, $cwd, $PHP_FAILED_TESTS;
1185 global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx;
1186 global $leak_check, $temp_source, $temp_target, $cfg, $environment;
1187 global $no_clean;
1188 global $valgrind_version;
1189 global $JUNIT;
1190 $temp_filenames = null;
1191 $org_file = $file;
1193 if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) {
1194 $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
1197 if (is_array($file)) {
1198 $file = $file[0];
1201 if ($DETAILED) echo "
1202 =================
1203 TEST $file
1206 // Load the sections of the test file.
1207 $section_text = array('TEST' => '');
1209 $fp = fopen($file, "rb") or error("Cannot open test file: $file");
1211 $borked = false;
1212 $bork_info = '';
1214 if (!feof($fp)) {
1215 $line = fgets($fp);
1217 if ($line === false) {
1218 $bork_info = "cannot read test";
1219 $borked = true;
1221 } else {
1222 $bork_info = "empty test [$file]";
1223 $borked = true;
1225 if (!$borked && strncmp('--TEST--', $line, 8)) {
1226 $bork_info = "tests must start with --TEST-- [$file]";
1227 $borked = true;
1230 $section = 'TEST';
1231 $secfile = false;
1232 $secdone = false;
1234 while (!feof($fp)) {
1235 $line = fgets($fp);
1237 if ($line === false) {
1238 break;
1241 // Match the beginning of a section.
1242 if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
1243 $section = $r[1];
1244 settype($section, 'string');
1246 if (isset($section_text[$section])) {
1247 $bork_info = "duplicated $section section";
1248 $borked = true;
1251 $section_text[$section] = '';
1252 $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL';
1253 $secdone = false;
1254 continue;
1257 // Add to the section text.
1258 if (!$secdone) {
1259 $section_text[$section] .= $line;
1262 // End of actual test?
1263 if ($secfile && preg_match('/^===DONE===\s*$/', $line)) {
1264 $secdone = true;
1268 // the redirect section allows a set of tests to be reused outside of
1269 // a given test dir
1270 if (!$borked) {
1271 if (@count($section_text['REDIRECTTEST']) == 1) {
1273 if ($IN_REDIRECT) {
1274 $borked = true;
1275 $bork_info = "Can't redirect a test from within a redirected test";
1276 } else {
1277 $borked = false;
1280 } else {
1282 if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) {
1283 $bork_info = "missing section --FILE--";
1284 $borked = true;
1287 if (@count($section_text['FILEEOF']) == 1) {
1288 $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']);
1289 unset($section_text['FILEEOF']);
1292 if (@count($section_text['FILE_EXTERNAL']) == 1) {
1293 // don't allow tests to retrieve files from anywhere but this subdirectory
1294 $section_text['FILE_EXTERNAL'] = dirname($file) . '/' . trim(str_replace('..', '', $section_text['FILE_EXTERNAL']));
1296 if (file_exists($section_text['FILE_EXTERNAL'])) {
1297 $section_text['FILE'] = file_get_contents($section_text['FILE_EXTERNAL'], FILE_BINARY);
1298 unset($section_text['FILE_EXTERNAL']);
1299 } else {
1300 $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']);
1301 $borked = true;
1305 if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) {
1306 $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
1307 $borked = true;
1311 fclose($fp);
1313 $shortname = str_replace($cwd . '/', '', $file);
1314 $tested_file = $shortname;
1316 if ($borked) {
1317 show_result("BORK", $bork_info, $tested_file);
1318 $PHP_FAILED_TESTS['BORKED'][] = array (
1319 'name' => $file,
1320 'test_name' => '',
1321 'output' => '',
1322 'diff' => '',
1323 'info' => "$bork_info [$file]",
1326 junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info);
1327 return 'BORKED';
1330 $tested = trim($section_text['TEST']);
1332 /* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */
1333 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'])) {
1334 if (isset($php_cgi)) {
1335 $old_php = $php;
1336 $php = $php_cgi . ' -C ';
1337 } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) {
1338 $old_php = $php;
1339 $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C ';
1340 } else {
1341 if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) {
1342 $old_php = $php;
1343 $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C ';
1344 } else if (file_exists("./sapi/cgi/php-cgi")) {
1345 $old_php = $php;
1346 $php = realpath("./sapi/cgi/php-cgi") . ' -C ';
1347 } else if (file_exists(dirname($php) . "/php-cgi")) {
1348 $old_php = $php;
1349 $php = realpath(dirname($php) . "/php-cgi") . ' -C ';
1350 } else {
1351 show_result('SKIP', $tested, $tested_file, "reason: CGI not available");
1353 junit_init_suite(junit_get_suitename_for($shortname));
1354 junit_mark_test_as('SKIP', $shortname, $tested, 0, 'CGI not available');
1355 return 'SKIPPED';
1360 show_test($test_idx, $shortname);
1362 if (is_array($IN_REDIRECT)) {
1363 $temp_dir = $test_dir = $IN_REDIRECT['dir'];
1364 } else {
1365 $temp_dir = $test_dir = realpath(dirname($file));
1368 if ($temp_source && $temp_target) {
1369 $temp_dir = str_replace($temp_source, $temp_target, $temp_dir);
1372 $main_file_name = basename($file,'phpt');
1374 $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff';
1375 $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log';
1376 $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp';
1377 $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out';
1378 $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem';
1379 $sh_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'sh';
1380 $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
1381 $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
1382 $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
1383 $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
1384 $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
1385 $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
1386 $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.');
1387 $tmp_relative_file = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $test_file) . 't';
1389 if ($temp_source && $temp_target) {
1390 $temp_skipif .= 's';
1391 $temp_file .= 's';
1392 $temp_clean .= 's';
1393 $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps';
1395 if (!is_dir(dirname($copy_file))) {
1396 mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file));
1399 if (isset($section_text['FILE'])) {
1400 save_text($copy_file, $section_text['FILE']);
1403 $temp_filenames = array(
1404 'file' => $copy_file,
1405 'diff' => $diff_filename,
1406 'log' => $log_filename,
1407 'exp' => $exp_filename,
1408 'out' => $output_filename,
1409 'mem' => $memcheck_filename,
1410 'sh' => $sh_filename,
1411 'php' => $temp_file,
1412 'skip' => $temp_skipif,
1413 'clean'=> $temp_clean);
1416 if (is_array($IN_REDIRECT)) {
1417 $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']);
1418 $tested_file = $tmp_relative_file;
1421 // unlink old test results
1422 @unlink($diff_filename);
1423 @unlink($log_filename);
1424 @unlink($exp_filename);
1425 @unlink($output_filename);
1426 @unlink($memcheck_filename);
1427 @unlink($sh_filename);
1428 @unlink($temp_file);
1429 @unlink($test_file);
1430 @unlink($temp_skipif);
1431 @unlink($test_skipif);
1432 @unlink($tmp_post);
1433 @unlink($temp_clean);
1434 @unlink($test_clean);
1436 // Reset environment from any previous test.
1437 $env['REDIRECT_STATUS'] = '';
1438 $env['QUERY_STRING'] = '';
1439 $env['PATH_TRANSLATED'] = '';
1440 $env['SCRIPT_FILENAME'] = '';
1441 $env['REQUEST_METHOD'] = '';
1442 $env['CONTENT_TYPE'] = '';
1443 $env['CONTENT_LENGTH'] = '';
1444 $env['TZ'] = '';
1446 if (!empty($section_text['ENV'])) {
1448 foreach(explode("\n", trim($section_text['ENV'])) as $e) {
1449 $e = explode('=', trim($e), 2);
1451 if (!empty($e[0]) && isset($e[1])) {
1452 $env[$e[0]] = $e[1];
1457 // Default ini settings
1458 $ini_settings = array();
1459 // additional ini overwrites
1460 //$ini_overwrites[] = 'setting=value';
1461 settings2array($ini_overwrites, $ini_settings);
1463 // Any special ini settings
1464 // these may overwrite the test defaults...
1465 if (array_key_exists('INI', $section_text)) {
1466 if (strpos($section_text['INI'], '{PWD}') !== false) {
1467 $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
1469 settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings);
1472 // Additional required extensions
1473 if (array_key_exists('EXTENSIONS', $section_text)) {
1474 $ext_dir=`$php -r 'echo ini_get("extension_dir");'`;
1475 $extensions = preg_split("/[\n\r]+/", trim($section_text['EXTENSIONS']));
1476 $loaded = explode(",", `$php -n -r 'echo join(",", get_loaded_extensions());'`);
1477 foreach ($extensions as $req_ext) {
1478 if (!in_array($req_ext, $loaded)) {
1479 $ini_settings['extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $req_ext . '.' . PHP_SHLIB_SUFFIX;
1484 settings2params($ini_settings);
1486 // Check if test should be skipped.
1487 $info = '';
1488 $warn = false;
1490 if (array_key_exists('SKIPIF', $section_text)) {
1492 if (trim($section_text['SKIPIF'])) {
1493 show_file_block('skip', $section_text['SKIPIF']);
1494 save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif);
1495 $extra = substr(PHP_OS, 0, 3) !== "WIN" ?
1496 "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
1498 if ($leak_check) {
1499 $env['USE_ZEND_ALLOC'] = '0';
1500 $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
1501 } else {
1502 $env['USE_ZEND_ALLOC'] = '1';
1503 $env['ZEND_DONT_UNLOAD_MODULES'] = 0;
1506 junit_start_timer($shortname);
1508 $output = system_with_timeout("$extra $php $pass_options -q $ini_settings -d display_errors=0 \"$test_skipif\"", $env);
1510 junit_finish_timer($shortname);
1512 if (!$cfg['keep']['skip']) {
1513 @unlink($test_skipif);
1516 if (!strncasecmp('skip', ltrim($output), 4)) {
1518 if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) {
1519 show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames);
1520 } else {
1521 show_result('SKIP', $tested, $tested_file, '', $temp_filenames);
1524 if (isset($old_php)) {
1525 $php = $old_php;
1528 if (!$cfg['keep']['skip']) {
1529 @unlink($test_skipif);
1532 $message = !empty($m[1]) ? $m[1] : '';
1533 junit_mark_test_as('SKIP', $shortname, $tested, null, $message);
1534 return 'SKIPPED';
1537 if (!strncasecmp('info', ltrim($output), 4)) {
1538 if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) {
1539 $info = " (info: $m[1])";
1543 if (!strncasecmp('warn', ltrim($output), 4)) {
1544 if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) {
1545 $warn = true; /* only if there is a reason */
1546 $info = " (warn: $m[1])";
1552 if (!extension_loaded("zlib")
1553 && ( array_key_exists("GZIP_POST", $section_text)
1554 || array_key_exists("DEFLATE_POST", $section_text))
1556 $message = "ext/zlib required";
1557 show_result('SKIP', $tested, $tested_file, "reason: $message", $temp_filenames);
1558 junit_mark_test_as('SKIP', $shortname, $tested, null, $message);
1559 return 'SKIPPED';
1562 if (@count($section_text['REDIRECTTEST']) == 1) {
1563 $test_files = array();
1565 $IN_REDIRECT = eval($section_text['REDIRECTTEST']);
1566 $IN_REDIRECT['via'] = "via [$shortname]\n\t";
1567 $IN_REDIRECT['dir'] = realpath(dirname($file));
1568 $IN_REDIRECT['prefix'] = trim($section_text['TEST']);
1570 if (count($IN_REDIRECT['TESTS']) == 1) {
1572 if (is_array($org_file)) {
1573 $test_files[] = $org_file[1];
1574 } else {
1575 $GLOBALS['test_files'] = $test_files;
1576 find_files($IN_REDIRECT['TESTS']);
1578 foreach($GLOBALS['test_files'] as $f) {
1579 $test_files[] = array($f, $file);
1582 $test_cnt += @count($test_files) - 1;
1583 $test_idx--;
1585 show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file);
1587 // set up environment
1588 $redirenv = array_merge($environment, $IN_REDIRECT['ENV']);
1589 $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR;
1591 usort($test_files, "test_sort");
1592 run_all_tests($test_files, $redirenv, $tested);
1594 show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file);
1596 // a redirected test never fails
1597 $IN_REDIRECT = false;
1599 junit_mark_test_as('PASS', $shortname, $tested);
1600 return 'REDIR';
1602 } else {
1604 $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory.";
1605 show_result("BORK", $bork_info, '', $temp_filenames);
1606 $PHP_FAILED_TESTS['BORKED'][] = array (
1607 'name' => $file,
1608 'test_name' => '',
1609 'output' => '',
1610 'diff' => '',
1611 'info' => "$bork_info [$file]",
1616 if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) {
1618 if (is_array($org_file)) {
1619 $file = $org_file[0];
1622 $bork_info = "Redirected test did not contain redirection info";
1623 show_result("BORK", $bork_info, '', $temp_filenames);
1624 $PHP_FAILED_TESTS['BORKED'][] = array (
1625 'name' => $file,
1626 'test_name' => '',
1627 'output' => '',
1628 'diff' => '',
1629 'info' => "$bork_info [$file]",
1632 junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info);
1634 return 'BORKED';
1637 // We've satisfied the preconditions - run the test!
1638 show_file_block('php', $section_text['FILE'], 'TEST');
1639 save_text($test_file, $section_text['FILE'], $temp_file);
1641 if (array_key_exists('GET', $section_text)) {
1642 $query_string = trim($section_text['GET']);
1643 } else {
1644 $query_string = '';
1647 $env['REDIRECT_STATUS'] = '1';
1648 $env['QUERY_STRING'] = $query_string;
1649 $env['PATH_TRANSLATED'] = $test_file;
1650 $env['SCRIPT_FILENAME'] = $test_file;
1652 if (array_key_exists('COOKIE', $section_text)) {
1653 $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
1654 } else {
1655 $env['HTTP_COOKIE'] = '';
1658 $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : '';
1660 if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
1662 $post = trim($section_text['POST_RAW']);
1663 $raw_lines = explode("\n", $post);
1665 $request = '';
1666 $started = false;
1668 foreach ($raw_lines as $line) {
1670 if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
1671 $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
1672 continue;
1675 if ($started) {
1676 $request .= "\n";
1679 $started = true;
1680 $request .= $line;
1683 $env['CONTENT_LENGTH'] = strlen($request);
1684 $env['REQUEST_METHOD'] = 'POST';
1686 if (empty($request)) {
1687 junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request');
1688 return 'BORKED';
1691 save_text($tmp_post, $request);
1692 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1694 } elseif (array_key_exists('PUT', $section_text) && !empty($section_text['PUT'])) {
1696 $post = trim($section_text['PUT']);
1697 $raw_lines = explode("\n", $post);
1699 $request = '';
1700 $started = false;
1702 foreach ($raw_lines as $line) {
1704 if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
1705 $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
1706 continue;
1709 if ($started) {
1710 $request .= "\n";
1713 $started = true;
1714 $request .= $line;
1717 $env['CONTENT_LENGTH'] = strlen($request);
1718 $env['REQUEST_METHOD'] = 'PUT';
1720 if (empty($request)) {
1721 junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request');
1722 return 'BORKED';
1725 save_text($tmp_post, $request);
1726 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1728 } else if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
1730 $post = trim($section_text['POST']);
1731 save_text($tmp_post, $post);
1732 $content_length = strlen($post);
1734 $env['REQUEST_METHOD'] = 'POST';
1735 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1736 $env['CONTENT_LENGTH'] = $content_length;
1738 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1740 } else if (array_key_exists('GZIP_POST', $section_text) && !empty($section_text['GZIP_POST'])) {
1742 $post = trim($section_text['GZIP_POST']);
1743 $post = gzencode($post, 9, FORCE_GZIP);
1744 $env['HTTP_CONTENT_ENCODING'] = 'gzip';
1746 save_text($tmp_post, $post);
1747 $content_length = strlen($post);
1749 $env['REQUEST_METHOD'] = 'POST';
1750 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1751 $env['CONTENT_LENGTH'] = $content_length;
1753 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1755 } else if (array_key_exists('DEFLATE_POST', $section_text) && !empty($section_text['DEFLATE_POST'])) {
1756 $post = trim($section_text['DEFLATE_POST']);
1757 $post = gzcompress($post, 9);
1758 $env['HTTP_CONTENT_ENCODING'] = 'deflate';
1759 save_text($tmp_post, $post);
1760 $content_length = strlen($post);
1762 $env['REQUEST_METHOD'] = 'POST';
1763 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1764 $env['CONTENT_LENGTH'] = $content_length;
1766 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\"";
1769 } else {
1771 $env['REQUEST_METHOD'] = 'GET';
1772 $env['CONTENT_TYPE'] = '';
1773 $env['CONTENT_LENGTH'] = '';
1775 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" $args 2>&1";
1778 if ($leak_check) {
1779 $env['USE_ZEND_ALLOC'] = '0';
1780 $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
1782 if (version_compare($valgrind_version, '3.3.0', '>=')) {
1783 /* valgrind 3.3.0+ doesn't have --log-file-exactly option */
1784 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file=$memcheck_filename $cmd";
1785 } else {
1786 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd";
1789 } else {
1790 $env['USE_ZEND_ALLOC'] = '1';
1791 $env['ZEND_DONT_UNLOAD_MODULES'] = 0;
1794 if ($DETAILED) echo "
1795 CONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . "
1796 CONTENT_TYPE = " . $env['CONTENT_TYPE'] . "
1797 PATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . "
1798 QUERY_STRING = " . $env['QUERY_STRING'] . "
1799 REDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . "
1800 REQUEST_METHOD = " . $env['REQUEST_METHOD'] . "
1801 SCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . "
1802 HTTP_COOKIE = " . $env['HTTP_COOKIE'] . "
1803 COMMAND $cmd
1806 junit_start_timer($shortname);
1808 $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null);
1810 junit_finish_timer($shortname);
1812 if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) {
1814 if (trim($section_text['CLEAN'])) {
1815 show_file_block('clean', $section_text['CLEAN']);
1816 save_text($test_clean, trim($section_text['CLEAN']), $temp_clean);
1818 if (!$no_clean) {
1819 $clean_params = array();
1820 settings2array($ini_overwrites, $clean_params);
1821 settings2params($clean_params);
1822 $extra = substr(PHP_OS, 0, 3) !== "WIN" ?
1823 "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
1824 system_with_timeout("$extra $php $pass_options -q $clean_params \"$test_clean\"", $env);
1827 if (!$cfg['keep']['clean']) {
1828 @unlink($test_clean);
1833 @unlink($tmp_post);
1835 $leaked = false;
1836 $passed = false;
1838 if ($leak_check) { // leak check
1839 $leaked = filesize($memcheck_filename) > 0;
1841 if (!$leaked) {
1842 @unlink($memcheck_filename);
1846 // Does the output match what is expected?
1847 $output = preg_replace("/\r\n/", "\n", trim($out));
1849 /* when using CGI, strip the headers from the output */
1850 $headers = "";
1852 if (isset($old_php) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
1853 $output = trim($match[2]);
1854 $rh = preg_split("/[\n\r]+/", $match[1]);
1855 $headers = array();
1857 foreach ($rh as $line) {
1858 if (strpos($line, ':') !== false) {
1859 $line = explode(':', $line, 2);
1860 $headers[trim($line[0])] = trim($line[1]);
1865 $failed_headers = false;
1867 if (isset($section_text['EXPECTHEADERS'])) {
1868 $want = array();
1869 $wanted_headers = array();
1870 $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']);
1872 foreach($lines as $line) {
1873 if (strpos($line, ':') !== false) {
1874 $line = explode(':', $line, 2);
1875 $want[trim($line[0])] = trim($line[1]);
1876 $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]);
1880 $org_headers = $headers;
1881 $headers = array();
1882 $output_headers = array();
1884 foreach($want as $k => $v) {
1886 if (isset($org_headers[$k])) {
1887 $headers = $org_headers[$k];
1888 $output_headers[] = $k . ': ' . $org_headers[$k];
1891 if (!isset($org_headers[$k]) || $org_headers[$k] != $v) {
1892 $failed_headers = true;
1896 ksort($wanted_headers);
1897 $wanted_headers = join("\n", $wanted_headers);
1898 ksort($output_headers);
1899 $output_headers = join("\n", $output_headers);
1902 show_file_block('out', $output);
1904 if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
1906 if (isset($section_text['EXPECTF'])) {
1907 $wanted = trim($section_text['EXPECTF']);
1908 } else {
1909 $wanted = trim($section_text['EXPECTREGEX']);
1912 show_file_block('exp', $wanted);
1913 $wanted_re = preg_replace('/\r\n/', "\n", $wanted);
1915 if (isset($section_text['EXPECTF'])) {
1917 // do preg_quote, but miss out any %r delimited sections
1918 $temp = "";
1919 $r = "%r";
1920 $startOffset = 0;
1921 $length = strlen($wanted_re);
1922 while($startOffset < $length) {
1923 $start = strpos($wanted_re, $r, $startOffset);
1924 if ($start !== false) {
1925 // we have found a start tag
1926 $end = strpos($wanted_re, $r, $start+2);
1927 if ($end === false) {
1928 // unbalanced tag, ignore it.
1929 $end = $start = $length;
1931 } else {
1932 // no more %r sections
1933 $start = $end = $length;
1935 // quote a non re portion of the string
1936 $temp = $temp . preg_quote(substr($wanted_re, $startOffset, ($start - $startOffset)), '/');
1937 // add the re unquoted.
1938 if ($end > $start) {
1939 $temp = $temp . '(' . substr($wanted_re, $start+2, ($end - $start-2)). ')';
1941 $startOffset = $end + 2;
1943 $wanted_re = $temp;
1945 $wanted_re = str_replace(
1946 array('%binary_string_optional%'),
1947 'string',
1948 $wanted_re
1950 $wanted_re = str_replace(
1951 array('%unicode_string_optional%'),
1952 'string',
1953 $wanted_re
1955 $wanted_re = str_replace(
1956 array('%unicode\|string%', '%string\|unicode%'),
1957 'string',
1958 $wanted_re
1960 $wanted_re = str_replace(
1961 array('%u\|b%', '%b\|u%'),
1963 $wanted_re
1965 // Stick to basics
1966 $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re);
1967 $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re);
1968 $wanted_re = str_replace('%S', '[^\r\n]*', $wanted_re);
1969 $wanted_re = str_replace('%a', '.+', $wanted_re);
1970 $wanted_re = str_replace('%A', '.*', $wanted_re);
1971 $wanted_re = str_replace('%w', '\s*', $wanted_re);
1972 $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re);
1973 $wanted_re = str_replace('%d', '\d+', $wanted_re);
1974 $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re);
1975 $wanted_re = str_replace('%f', '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', $wanted_re);
1976 $wanted_re = str_replace('%c', '.', $wanted_re);
1977 // %f allows two points "-.0.0" but that is the best *simple* expression
1979 /* DEBUG YOUR REGEX HERE
1980 var_dump($wanted_re);
1981 print(str_repeat('=', 80) . "\n");
1982 var_dump($output);
1984 if (preg_match("/^$wanted_re\$/s", $output)) {
1985 $passed = true;
1986 if (!$cfg['keep']['php']) {
1987 @unlink($test_file);
1989 if (isset($old_php)) {
1990 $php = $old_php;
1993 if (!$leaked && !$failed_headers) {
1994 if (isset($section_text['XFAIL'] )) {
1995 $warn = true;
1996 $info = " (warn: XFAIL section but test passes)";
1997 }else {
1998 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
1999 junit_mark_test_as('PASS', $shortname, $tested);
2000 return 'PASSED';
2005 } else {
2007 $wanted = trim($section_text['EXPECT']);
2008 $wanted = preg_replace('/\r\n/',"\n", $wanted);
2009 show_file_block('exp', $wanted);
2011 // compare and leave on success
2012 if (!strcmp($output, $wanted)) {
2013 $passed = true;
2015 if (!$cfg['keep']['php']) {
2016 @unlink($test_file);
2019 if (isset($old_php)) {
2020 $php = $old_php;
2023 if (!$leaked && !$failed_headers) {
2024 if (isset($section_text['XFAIL'] )) {
2025 $warn = true;
2026 $info = " (warn: XFAIL section but test passes)";
2027 }else {
2028 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
2029 junit_mark_test_as('PASS', $shortname, $tested);
2030 return 'PASSED';
2035 $wanted_re = null;
2038 // Test failed so we need to report details.
2039 if ($failed_headers) {
2040 $passed = false;
2041 $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted;
2042 $output = $output_headers . "\n--HEADERS--\n" . $output;
2044 if (isset($wanted_re)) {
2045 $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re;
2049 if ($leaked) {
2050 $restype[] = 'LEAK';
2053 if ($warn) {
2054 $restype[] = 'WARN';
2057 if (!$passed) {
2058 if (isset($section_text['XFAIL'])) {
2059 $restype[] = 'XFAIL';
2060 $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']);
2061 } else {
2062 $restype[] = 'FAIL';
2066 if (!$passed) {
2068 // write .exp
2069 if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, $wanted, FILE_BINARY) === false) {
2070 error("Cannot create expected test output - $exp_filename");
2073 // write .out
2074 if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) {
2075 error("Cannot create test output - $output_filename");
2078 // write .diff
2079 $diff = generate_diff($wanted, $wanted_re, $output);
2080 if (is_array($IN_REDIRECT)) {
2081 $diff = "# original source file: $shortname\n" . $diff;
2083 show_file_block('diff', $diff);
2084 if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, $diff, FILE_BINARY) === false) {
2085 error("Cannot create test diff - $diff_filename");
2088 // write .sh
2089 if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh
2091 {$cmd}
2092 ", FILE_BINARY) === false) {
2093 error("Cannot create test shell script - $sh_filename");
2095 chmod($sh_filename, 0755);
2097 // write .log
2098 if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, "
2099 ---- EXPECTED OUTPUT
2100 $wanted
2101 ---- ACTUAL OUTPUT
2102 $output
2103 ---- FAILED
2104 ", FILE_BINARY) === false) {
2105 error("Cannot create test log - $log_filename");
2106 error_report($file, $log_filename, $tested);
2110 show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames);
2112 foreach ($restype as $type) {
2113 $PHP_FAILED_TESTS[$type.'ED'][] = array (
2114 'name' => $file,
2115 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]",
2116 'output' => $output_filename,
2117 'diff' => $diff_filename,
2118 'info' => $info,
2122 if (isset($old_php)) {
2123 $php = $old_php;
2126 $diff = empty($diff) ? '' : preg_replace('/\e/', '<esc>', $diff);
2128 junit_mark_test_as($restype, str_replace($cwd . '/', '', $tested_file), $tested, null, $info, $diff);
2130 return $restype[0] . 'ED';
2133 function comp_line($l1, $l2, $is_reg)
2135 if ($is_reg) {
2136 return preg_match('/^'. $l1 . '$/s', $l2);
2137 } else {
2138 return !strcmp($l1, $l2);
2142 function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps)
2144 $equal = 0;
2146 while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
2147 $idx1++;
2148 $idx2++;
2149 $equal++;
2150 $steps--;
2152 if (--$steps > 0) {
2153 $eq1 = 0;
2154 $st = $steps / 2;
2156 for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) {
2157 $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st);
2159 if ($eq > $eq1) {
2160 $eq1 = $eq;
2164 $eq2 = 0;
2165 $st = $steps;
2167 for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) {
2168 $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st);
2169 if ($eq > $eq2) {
2170 $eq2 = $eq;
2174 if ($eq1 > $eq2) {
2175 $equal += $eq1;
2176 } else if ($eq2 > 0) {
2177 $equal += $eq2;
2181 return $equal;
2184 function generate_array_diff($ar1, $ar2, $is_reg, $w)
2186 $idx1 = 0; $ofs1 = 0; $cnt1 = @count($ar1);
2187 $idx2 = 0; $ofs2 = 0; $cnt2 = @count($ar2);
2188 $diff = array();
2189 $old1 = array();
2190 $old2 = array();
2192 while ($idx1 < $cnt1 && $idx2 < $cnt2) {
2194 if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
2195 $idx1++;
2196 $idx2++;
2197 continue;
2198 } else {
2200 $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1+1, $idx2, $cnt1, $cnt2, 10);
2201 $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2+1, $cnt1, $cnt2, 10);
2203 if ($c1 > $c2) {
2204 $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++];
2205 $last = 1;
2206 } else if ($c2 > 0) {
2207 $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++];
2208 $last = 2;
2209 } else {
2210 $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++];
2211 $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++];
2216 reset($old1); $k1 = key($old1); $l1 = -2;
2217 reset($old2); $k2 = key($old2); $l2 = -2;
2219 while ($k1 !== null || $k2 !== null) {
2221 if ($k1 == $l1 + 1 || $k2 === null) {
2222 $l1 = $k1;
2223 $diff[] = current($old1);
2224 $k1 = next($old1) ? key($old1) : null;
2225 } else if ($k2 == $l2 + 1 || $k1 === null) {
2226 $l2 = $k2;
2227 $diff[] = current($old2);
2228 $k2 = next($old2) ? key($old2) : null;
2229 } else if ($k1 < $k2) {
2230 $l1 = $k1;
2231 $diff[] = current($old1);
2232 $k1 = next($old1) ? key($old1) : null;
2233 } else {
2234 $l2 = $k2;
2235 $diff[] = current($old2);
2236 $k2 = next($old2) ? key($old2) : null;
2240 while ($idx1 < $cnt1) {
2241 $diff[] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++];
2244 while ($idx2 < $cnt2) {
2245 $diff[] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++];
2248 return $diff;
2251 function generate_diff($wanted, $wanted_re, $output)
2253 $w = explode("\n", $wanted);
2254 $o = explode("\n", $output);
2255 $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re);
2256 $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w);
2258 return implode("\r\n", $diff);
2261 function error($message)
2263 echo "ERROR: {$message}\n";
2264 exit(1);
2267 function settings2array($settings, &$ini_settings)
2269 foreach($settings as $setting) {
2271 if (strpos($setting, '=') !== false) {
2272 $setting = explode("=", $setting, 2);
2273 $name = trim($setting[0]);
2274 $value = trim($setting[1]);
2276 if ($name == 'extension') {
2278 if (!isset($ini_settings[$name])) {
2279 $ini_settings[$name] = array();
2282 $ini_settings[$name][] = $value;
2284 } else {
2285 $ini_settings[$name] = $value;
2291 function settings2params(&$ini_settings)
2293 $settings = '';
2295 foreach($ini_settings as $name => $value) {
2297 if (is_array($value)) {
2298 foreach($value as $val) {
2299 $val = addslashes($val);
2300 $settings .= " -d \"$name=$val\"";
2302 } else {
2303 if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value{0} == '"') {
2304 $len = strlen($value);
2306 if ($value{$len - 1} == '"') {
2307 $value{0} = "'";
2308 $value{$len - 1} = "'";
2310 } else {
2311 $value = addslashes($value);
2314 $settings .= " -d \"$name=$value\"";
2318 $ini_settings = $settings;
2321 function compute_summary()
2323 global $n_total, $test_results, $ignored_by_ext, $sum_results, $percent_results;
2325 $n_total = count($test_results);
2326 $n_total += $ignored_by_ext;
2327 $sum_results = array(
2328 'PASSED' => 0,
2329 'WARNED' => 0,
2330 'SKIPPED' => 0,
2331 'FAILED' => 0,
2332 'BORKED' => 0,
2333 'LEAKED' => 0,
2334 'XFAILED' => 0
2337 foreach ($test_results as $v) {
2338 $sum_results[$v]++;
2341 $sum_results['SKIPPED'] += $ignored_by_ext;
2342 $percent_results = array();
2344 while (list($v, $n) = each($sum_results)) {
2345 $percent_results[$v] = (100.0 * $n) / $n_total;
2349 function get_summary($show_ext_summary, $show_html)
2351 global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $leak_check;
2353 $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED'];
2355 if ($x_total) {
2356 $x_warned = (100.0 * $sum_results['WARNED']) / $x_total;
2357 $x_failed = (100.0 * $sum_results['FAILED']) / $x_total;
2358 $x_xfailed = (100.0 * $sum_results['XFAILED']) / $x_total;
2359 $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total;
2360 $x_passed = (100.0 * $sum_results['PASSED']) / $x_total;
2361 } else {
2362 $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = 0;
2365 $summary = '';
2367 if ($show_html) {
2368 $summary .= "<pre>\n";
2371 if ($show_ext_summary) {
2372 $summary .= '
2373 =====================================================================
2374 TEST RESULT SUMMARY
2375 ---------------------------------------------------------------------
2376 Exts skipped : ' . sprintf('%4d', $exts_skipped) . '
2377 Exts tested : ' . sprintf('%4d', $exts_tested) . '
2378 ---------------------------------------------------------------------
2382 $summary .= '
2383 Number of tests : ' . sprintf('%4d', $n_total) . ' ' . sprintf('%8d', $x_total);
2385 if ($sum_results['BORKED']) {
2386 $summary .= '
2387 Tests borked : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------';
2390 $summary .= '
2391 Tests skipped : ' . sprintf('%4d (%5.1f%%)', $sum_results['SKIPPED'], $percent_results['SKIPPED']) . ' --------
2392 Tests warned : ' . sprintf('%4d (%5.1f%%)', $sum_results['WARNED'], $percent_results['WARNED']) . ' ' . sprintf('(%5.1f%%)', $x_warned) . '
2393 Tests failed : ' . sprintf('%4d (%5.1f%%)', $sum_results['FAILED'], $percent_results['FAILED']) . ' ' . sprintf('(%5.1f%%)', $x_failed) . '
2394 Expected fail : ' . sprintf('%4d (%5.1f%%)', $sum_results['XFAILED'], $percent_results['XFAILED']) . ' ' . sprintf('(%5.1f%%)', $x_xfailed);
2396 if ($leak_check) {
2397 $summary .= '
2398 Tests leaked : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked);
2401 $summary .= '
2402 Tests passed : ' . sprintf('%4d (%5.1f%%)', $sum_results['PASSED'], $percent_results['PASSED']) . ' ' . sprintf('(%5.1f%%)', $x_passed) . '
2403 ---------------------------------------------------------------------
2404 Time taken : ' . sprintf('%4d seconds', $end_time - $start_time) . '
2405 =====================================================================
2407 $failed_test_summary = '';
2409 if (count($PHP_FAILED_TESTS['XFAILED'])) {
2410 $failed_test_summary .= '
2411 =====================================================================
2412 EXPECTED FAILED TEST SUMMARY
2413 ---------------------------------------------------------------------
2415 foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) {
2416 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
2418 $failed_test_summary .= "=====================================================================\n";
2421 if (count($PHP_FAILED_TESTS['BORKED'])) {
2422 $failed_test_summary .= '
2423 =====================================================================
2424 BORKED TEST SUMMARY
2425 ---------------------------------------------------------------------
2427 foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) {
2428 $failed_test_summary .= $failed_test_data['info'] . "\n";
2431 $failed_test_summary .= "=====================================================================\n";
2434 if (count($PHP_FAILED_TESTS['FAILED'])) {
2435 $failed_test_summary .= '
2436 =====================================================================
2437 FAILED TEST SUMMARY
2438 ---------------------------------------------------------------------
2440 foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) {
2441 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
2443 $failed_test_summary .= "=====================================================================\n";
2445 if (count($PHP_FAILED_TESTS['WARNED'])) {
2446 $failed_test_summary .= '
2447 =====================================================================
2448 WARNED TEST SUMMARY
2449 ---------------------------------------------------------------------
2451 foreach ($PHP_FAILED_TESTS['WARNED'] as $failed_test_data) {
2452 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
2455 $failed_test_summary .= "=====================================================================\n";
2458 if (count($PHP_FAILED_TESTS['LEAKED'])) {
2459 $failed_test_summary .= '
2460 =====================================================================
2461 LEAKED TEST SUMMARY
2462 ---------------------------------------------------------------------
2464 foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) {
2465 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
2468 $failed_test_summary .= "=====================================================================\n";
2471 if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) {
2472 $summary .= $failed_test_summary;
2475 if ($show_html) {
2476 $summary .= "</pre>";
2479 return $summary;
2482 function show_start($start_time)
2484 global $html_output, $html_file;
2486 if ($html_output) {
2487 fwrite($html_file, "<h2>Time Start: " . date('Y-m-d H:i:s', $start_time) . "</h2>\n");
2488 fwrite($html_file, "<table>\n");
2491 echo "TIME START " . date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n";
2494 function show_end($end_time)
2496 global $html_output, $html_file;
2498 if ($html_output) {
2499 fwrite($html_file, "</table>\n");
2500 fwrite($html_file, "<h2>Time End: " . date('Y-m-d H:i:s', $end_time) . "</h2>\n");
2503 echo "=====================================================================\nTIME END " . date('Y-m-d H:i:s', $end_time) . "\n";
2506 function show_summary()
2508 global $html_output, $html_file;
2510 if ($html_output) {
2511 fwrite($html_file, "<hr/>\n" . get_summary(true, true));
2514 echo get_summary(true, false);
2517 function show_redirect_start($tests, $tested, $tested_file)
2519 global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS;
2521 if ($html_output) {
2522 fwrite($html_file, "<tr><td colspan='3'>---&gt; $tests ($tested [$tested_file]) begin</td></tr>\n");
2525 if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) {
2526 echo "REDIRECT $tests ($tested [$tested_file]) begin\n";
2527 } else {
2528 // Write over the last line to avoid random trailing chars on next echo
2529 echo str_repeat(" ", $line_length), "\r";
2533 function show_redirect_ends($tests, $tested, $tested_file)
2535 global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS;
2537 if ($html_output) {
2538 fwrite($html_file, "<tr><td colspan='3'>---&gt; $tests ($tested [$tested_file]) done</td></tr>\n");
2541 if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) {
2542 echo "REDIRECT $tests ($tested [$tested_file]) done\n";
2543 } else {
2544 // Write over the last line to avoid random trailing chars on next echo
2545 echo str_repeat(" ", $line_length), "\r";
2549 function show_test($test_idx, $shortname)
2551 global $test_cnt;
2552 global $line_length;
2554 $str = "TEST $test_idx/$test_cnt [$shortname]\r";
2555 $line_length = strlen($str);
2556 echo $str;
2557 flush();
2560 function show_result($result, $tested, $tested_file, $extra = '', $temp_filenames = null)
2562 global $html_output, $html_file, $temp_target, $temp_urlbase, $line_length, $SHOW_ONLY_GROUPS;
2564 if (!$SHOW_ONLY_GROUPS || in_array($result, $SHOW_ONLY_GROUPS)) {
2565 echo "$result $tested [$tested_file] $extra\n";
2566 } else {
2567 // Write over the last line to avoid random trailing chars on next echo
2568 echo str_repeat(" ", $line_length), "\r";
2571 if ($html_output) {
2573 if (isset($temp_filenames['file']) && file_exists($temp_filenames['file'])) {
2574 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']);
2575 $tested = "<a href='$url'>$tested</a>";
2578 if (isset($temp_filenames['skip']) && file_exists($temp_filenames['skip'])) {
2580 if (empty($extra)) {
2581 $extra = "skipif";
2584 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']);
2585 $extra = "<a href='$url'>$extra</a>";
2587 } else if (empty($extra)) {
2588 $extra = "&nbsp;";
2591 if (isset($temp_filenames['diff']) && file_exists($temp_filenames['diff'])) {
2592 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']);
2593 $diff = "<a href='$url'>diff</a>";
2594 } else {
2595 $diff = "&nbsp;";
2598 if (isset($temp_filenames['mem']) && file_exists($temp_filenames['mem'])) {
2599 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']);
2600 $mem = "<a href='$url'>leaks</a>";
2601 } else {
2602 $mem = "&nbsp;";
2605 fwrite($html_file,
2606 "<tr>" .
2607 "<td>$result</td>" .
2608 "<td>$tested</td>" .
2609 "<td>$extra</td>" .
2610 "<td>$diff</td>" .
2611 "<td>$mem</td>" .
2612 "</tr>\n");
2616 function junit_init() {
2617 // Check whether a junit log is wanted.
2618 $JUNIT = getenv('TEST_PHP_JUNIT');
2619 if (empty($JUNIT)) {
2620 $JUNIT = FALSE;
2621 } elseif (!$fp = fopen($JUNIT, 'w')) {
2622 error("Failed to open $JUNIT for writing.");
2623 } else {
2624 $JUNIT = array(
2625 'fp' => $fp,
2626 'name' => 'php-src',
2627 'test_total' => 0,
2628 'test_pass' => 0,
2629 'test_fail' => 0,
2630 'test_error' => 0,
2631 'test_skip' => 0,
2632 'execution_time'=> 0,
2633 'suites' => array(),
2634 'files' => array()
2638 $GLOBALS['JUNIT'] = $JUNIT;
2641 function junit_save_xml() {
2642 global $JUNIT;
2643 if (!junit_enabled()) return;
2645 $xml = '<?xml version="1.0" encoding="UTF-8"?>'. PHP_EOL .
2646 '<testsuites>' . PHP_EOL;
2647 $xml .= junit_get_suite_xml();
2648 $xml .= '</testsuites>';
2649 fwrite($JUNIT['fp'], $xml);
2652 function junit_get_suite_xml($suite_name = '') {
2653 global $JUNIT;
2655 $suite = $suite_name ? $JUNIT['suites'][$suite_name] : $JUNIT;
2657 $result = sprintf(
2658 '<testsuite name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL,
2659 $suite['name'], $suite['test_total'], $suite['test_fail'], $suite['test_error'], $suite['test_skip'],
2660 $suite['execution_time']
2663 foreach($suite['suites'] as $sub_suite) {
2664 $result .= junit_get_suite_xml($sub_suite['name']);
2667 // Output files only in subsuites
2668 if (!empty($suite_name)) {
2669 foreach($suite['files'] as $file) {
2670 $result .= $JUNIT['files'][$file]['xml'];
2674 $result .= '</testsuite>' . PHP_EOL;
2676 return $result;
2679 function junit_enabled() {
2680 global $JUNIT;
2681 return !empty($JUNIT);
2685 * @param array|string $type
2686 * @param string $file_name
2687 * @param string $test_name
2688 * @param int|string $time
2689 * @param string $message
2690 * @param string $details
2691 * @return void
2693 function junit_mark_test_as($type, $file_name, $test_name, $time = null, $message = '', $details = '') {
2694 global $JUNIT;
2695 if (!junit_enabled()) return;
2697 $suite = junit_get_suitename_for($file_name);
2699 junit_suite_record($suite, 'test_total');
2701 $time = null !== $time ? $time : junit_get_timer($file_name);
2702 junit_suite_record($suite, 'execution_time', $time);
2704 $escaped_details = htmlspecialchars($details, ENT_QUOTES, 'UTF-8');
2705 $escaped_details = preg_replace_callback('/[\0-\x08\x0B\x0C\x0E-\x1F]/', function ($c) {
2706 return sprintf('[[0x%02x]]', ord($c[0]));
2707 }, $escaped_details);
2708 $escaped_message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
2710 $escaped_test_name = basename($file_name) . ' - ' . htmlspecialchars($test_name, ENT_QUOTES);
2711 $JUNIT['files'][$file_name]['xml'] = "<testcase classname='$suite' name='$escaped_test_name' time='$time'>\n";
2713 if (is_array($type)) {
2714 $output_type = $type[0] . 'ED';
2715 $temp = array_intersect(array('XFAIL', 'FAIL'), $type);
2716 $type = reset($temp);
2717 } else {
2718 $output_type = $type . 'ED';
2721 if ('PASS' == $type || 'XFAIL' == $type) {
2722 junit_suite_record($suite, 'test_pass');
2723 } elseif ('BORK' == $type) {
2724 junit_suite_record($suite, 'test_error');
2725 $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$escaped_message'/>\n";
2726 } elseif ('SKIP' == $type) {
2727 junit_suite_record($suite, 'test_skip');
2728 $JUNIT['files'][$file_name]['xml'] .= "<skipped>$escaped_message</skipped>\n";
2729 } elseif('FAIL' == $type) {
2730 junit_suite_record($suite, 'test_fail');
2731 $JUNIT['files'][$file_name]['xml'] .= "<failure type='$output_type' message='$escaped_message'>$escaped_details</failure>\n";
2732 } else {
2733 junit_suite_record($suite, 'test_error');
2734 $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$escaped_message'>$escaped_details</error>\n";
2737 $JUNIT['files'][$file_name]['xml'] .= "</testcase>\n";
2741 function junit_suite_record($suite, $param, $value = 1) {
2742 global $JUNIT;
2744 $JUNIT[$param] += $value;
2745 $JUNIT['suites'][$suite][$param] += $value;
2748 function junit_get_timer($file_name) {
2749 global $JUNIT;
2750 if (!junit_enabled()) return 0;
2752 if (isset($JUNIT['files'][$file_name]['total'])) {
2753 return number_format($JUNIT['files'][$file_name]['total'], 4);
2756 return 0;
2759 function junit_start_timer($file_name) {
2760 global $JUNIT;
2761 if (!junit_enabled()) return;
2763 if (!isset($JUNIT['files'][$file_name]['start'])) {
2764 $JUNIT['files'][$file_name]['start'] = microtime(true);
2766 $suite = junit_get_suitename_for($file_name);
2767 junit_init_suite($suite);
2768 $JUNIT['suites'][$suite]['files'][$file_name] = $file_name;
2772 function junit_get_suitename_for($file_name) {
2773 return junit_path_to_classname(dirname($file_name));
2776 function junit_path_to_classname($file_name) {
2777 global $JUNIT;
2778 return $JUNIT['name'] . '.' . str_replace(DIRECTORY_SEPARATOR, '.', $file_name);
2781 function junit_init_suite($suite_name) {
2782 global $JUNIT;
2783 if (!junit_enabled()) return;
2785 if (!empty($JUNIT['suites'][$suite_name])) {
2786 return;
2789 $JUNIT['suites'][$suite_name] = array(
2790 'name' => $suite_name,
2791 'test_total' => 0,
2792 'test_pass' => 0,
2793 'test_fail' => 0,
2794 'test_error' => 0,
2795 'test_skip' => 0,
2796 'suites' => array(),
2797 'files' => array(),
2798 'execution_time'=> 0,
2802 function junit_finish_timer($file_name) {
2803 global $JUNIT;
2804 if (!junit_enabled()) return;
2806 if (!isset($JUNIT['files'][$file_name]['start'])) {
2807 error("Timer for $file_name was not started!");
2810 if (!isset($JUNIT['files'][$file_name]['total'])) {
2811 $JUNIT['files'][$file_name]['total'] = 0;
2814 $start = $JUNIT['files'][$file_name]['start'];
2815 $JUNIT['files'][$file_name]['total'] += microtime(true) - $start;
2816 unset($JUNIT['files'][$file_name]['start']);
2820 * Local variables:
2821 * tab-width: 4
2822 * c-basic-offset: 4
2823 * End:
2824 * vim: noet sw=4 ts=4