4 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
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
34 if (!extension_loaded('pcre')) {
37 +-----------------------------------------------------------+
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 +-----------------------------------------------------------+
49 if (!function_exists('proc_open')) {
50 echo <<<NO_PROC_OPEN_ERROR
52 +-----------------------------------------------------------+
54 | The test-suite requires that proc_open() is available. |
55 | Please check if you disabled it in php.ini. |
56 +-----------------------------------------------------------+
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
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
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');
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 +-----------------------------------------------------------+
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 +-----------------------------------------------------------+
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!
146 if (getenv('TEST_PHP_EXECUTABLE')) {
147 $php = getenv('TEST_PHP_EXECUTABLE');
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");
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()
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'));
193 $log_format = 'LEODS';
196 // Check whether a detailed log is wanted.
197 if (getenv('TEST_PHP_DETAILED')) {
198 $DETAILED = getenv('TEST_PHP_DETAILED');
205 if (getenv('SHOW_ONLY_GROUPS')) {
206 $SHOW_ONLY_GROUPS = explode(",", getenv('SHOW_ONLY_GROUPS'));
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'));
215 $user_tests = array();
218 $exts_to_test = array();
219 $ini_overwrites = array(
223 'disable_functions=',
224 'output_buffering=Off',
225 'error_reporting=' . (E_ALL | E_STRICT),
227 'display_startup_errors=1',
232 'report_zend_debug=0',
235 'error_prepend_string=',
236 'error_append_string=',
237 'auto_prepend_file=',
239 'magic_quotes_runtime=0',
240 'ignore_repeated_errors=0',
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;
250 $info_file = __DIR__ . '/run-test-info.php';
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";
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);
296 // Write test context information.
298 =====================================================================
299 PHP : $php $php_info $php_cgi_info
302 foreach ($user_tests as $test_dir) {
303 echo "{$test_dir}\n ";
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]: ";
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
346 if ($just_save_results) {
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): ";
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";
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');
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');
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");
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";
436 fwrite($fp, "\nThank you for helping to make PHP better.\n");
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;
456 $output_file = $CUR_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt';
459 $output_file = 'compress.zlib://' . $output_file . '.gz';
462 $just_save_results = false;
464 $html_output = false;
468 $temp_urlbase = null;
472 $cfgtypes = array('show', 'keep');
473 $cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp');
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++) {
498 $switch = substr($argv[$i],1,1);
499 $repeat = substr($argv[$i],0,1) == '-';
504 $switch = substr($argv[$i],1,1);
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;
533 $test_list = file($argv[++$i]);
535 foreach($test_list as $test) {
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') {
548 // break left intentionally
550 $failed_tests_file = fopen($argv[++$i], 'w+t');
553 $failed_tests_file = fopen($argv[++$i], 'a+t');
556 $conf_passed = $argv[++$i];
559 $ini_overwrites[] = $argv[++$i];
562 $SHOW_ONLY_GROUPS = explode(",", $argv[++$i]);;
566 foreach($cfgfiles as $file) {
567 $cfg['keep'][$file] = true;
573 $valgrind_cmd = "valgrind --version";
574 $valgrind_header = system_with_timeout($valgrind_cmd, $environment);
576 if (!$valgrind_header) {
577 error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed.");
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);
587 if (!$pass_option_n) {
588 $pass_options .= ' -n';
590 $pass_option_n = true;
597 putenv("TEST_PHP_EXECUTABLE=$php");
598 $environment['TEST_PHP_EXECUTABLE'] = $php;
601 putenv('NO_INTERACTION=1');
605 $output_file = $argv[++$i];
606 $just_save_results = true;
608 case '--set-timeout':
609 $environment['TEST_TIMEOUT'] = $argv[++$i];
612 foreach($cfgfiles as $file) {
613 $cfg['show'][$file] = true;
616 case '--temp-source':
617 $temp_source = $argv[++$i];
619 case '--temp-target':
620 $temp_target = $argv[++$i];
622 $temp_urlbase = $temp_target;
625 case '--temp-urlbase':
626 $temp_urlbase = $argv[++$i];
633 $environment['SKIP_SLOW_TESTS'] = 1;
636 $environment['SKIP_ONLINE_TESTS'] = 1;
640 // repeat check with full switch
642 if ($switch != '-') {
647 $html_file = fopen($argv[++$i], 'wt');
648 $html_output = is_resource($html_file);
655 echo "Illegal switch '$switch' specified!\n";
661 php run-tests.php [options] [files] [directories]
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
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.
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'
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.
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');
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;
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);
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);
778 putenv('NO_INTERACTION=1');
780 write_information($html_output);
781 usort($test_files, "test_sort");
782 $start_time = time();
785 echo "Running selected tests.\n";
787 show_start($start_time);
791 run_all_tests($test_files, $environment);
798 if ($failed_tests_file) {
799 fclose($failed_tests_file);
802 if (count($test_files) || count($test_results)) {
805 fwrite($html_file, "<hr/>\n" . get_summary(false, true));
807 echo "=====================================================================";
808 echo get_summary(false, false);
815 if ($output_file != '' && $just_save_results) {
816 save_or_mail_results();
821 if (getenv('REPORT_EXIT_STATUS') == 1 and preg_match('/FAILED(?: |$)/', implode(' ', $test_results))) {
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);
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') {
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));
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");
882 // Otherwise we're only interested in *.phpt files.
883 if (substr($name, -5) == '.phpt') {
887 $testfile = realpath("{$dir}/{$name}");
888 $test_files[] = $testfile;
896 function test_name($name)
898 if (is_array($name)) {
899 return $name[0] . ':' . $name[1];
905 function test_sort($a, $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;
916 return strcmp($a, $b);
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);
930 run_all_tests($test_files, $environment);
933 if ($failed_tests_file) {
934 fclose($failed_tests_file);
939 if (0 == count($test_results)) {
940 echo "No tests were run.\n";
953 save_or_mail_results();
957 if (getenv('REPORT_EXIT_STATUS') == 1 and $sum_results['FAILED']) {
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'])) {
977 $port = $proxy['port'];
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);
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");
1002 fwrite($fs, "\r\n\r\n");
1010 // Write the given text to a temporary file, and return the filename.
1013 function save_text($filename, $text, $filename_copy = null)
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 "
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'))) {
1045 echo $testname . "(1) : $tested\n";
1046 echo $logname . "(1) : $tested\n";
1049 echo $testname . ":1: $tested\n";
1050 echo $logname . ":1: $tested\n";
1055 function system_with_timeout($commandline, $env = null, $stdin = null)
1057 global $leak_check, $cwd;
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));
1076 if (!is_null($stdin)) {
1077 fwrite($pipes[0], $stdin);
1081 $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60);
1084 /* hide errors from interrupted syscalls */
1089 $n = @stream_select($r, $w, $e, $timeout);
1093 } else if ($n === 0) {
1095 $data .= "\n ** ERROR: process timed out **\n";
1096 proc_terminate($proc, 9);
1098 } else if ($n > 0) {
1099 $line = fread($pipes[1], 8192);
1100 if (strlen($line) == 0) {
1108 $stat = proc_get_status($proc);
1110 if ($stat['signaled']) {
1111 $data .= "\nTermsig=" . $stat['stopsig'];
1114 $code = proc_close($proc);
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) {
1130 } else if ($redir_tested) {
1131 $index = "# $redir_tested: $name";
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)
1154 if ($cfg['show'][$file]) {
1156 if (is_null($section)) {
1157 $section = strtoupper($file);
1160 echo "\n========" . $section . "========\n";
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;
1175 global $valgrind_version;
1177 $temp_filenames = null;
1180 if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) {
1181 $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
1184 if (is_array($file)) {
1188 if ($DETAILED) echo "
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");
1204 if ($line === false) {
1205 $bork_info = "cannot read test";
1209 $bork_info = "empty test [$file]";
1212 if (!$borked && strncmp('--TEST--', $line, 8)) {
1213 $bork_info = "tests must start with --TEST-- [$file]";
1221 while (!feof($fp)) {
1224 if ($line === false) {
1228 // Match the beginning of a section.
1229 if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
1231 settype($section, 'string');
1233 if (isset($section_text[$section])) {
1234 $bork_info = "duplicated $section section";
1238 $section_text[$section] = '';
1239 $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL';
1244 // Add to the section text.
1246 $section_text[$section] .= $line;
1249 // End of actual test?
1250 if ($secfile && preg_match('/^===DONE===\s*$/', $line)) {
1255 // the redirect section allows a set of tests to be reused outside of
1258 if (@count($section_text['REDIRECTTEST']) == 1) {
1262 $bork_info = "Can't redirect a test from within a redirected test";
1269 if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) {
1270 $bork_info = "missing section --FILE--";
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']);
1287 $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']);
1292 if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) {
1293 $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
1300 $shortname = str_replace($cwd . '/', '', $file);
1301 $tested_file = $shortname;
1304 show_result("BORK", $bork_info, $tested_file);
1305 $PHP_FAILED_TESTS['BORKED'][] = array (
1310 'info' => "$bork_info [$file]",
1313 junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info);
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)) {
1323 $php = $php_cgi . ' -C ';
1324 } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) {
1326 $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C ';
1328 if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) {
1330 $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C ';
1331 } else if (file_exists("./sapi/cgi/php-cgi")) {
1333 $php = realpath("./sapi/cgi/php-cgi") . ' -C ';
1334 } else if (file_exists(dirname($php) . "/php-cgi")) {
1336 $php = realpath(dirname($php) . "/php-cgi") . ' -C ';
1338 show_result('SKIP', $tested, $tested_file, "reason: CGI not available");
1340 junit_mark_test_as('SKIP', $shortname, $tested, 0, 'CGI not available');
1346 show_test($test_idx, $shortname);
1348 if (is_array($IN_REDIRECT)) {
1349 $temp_dir = $test_dir = $IN_REDIRECT['dir'];
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';
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);
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'] = '';
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.
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;": "";
1485 $env['USE_ZEND_ALLOC'] = '0';
1486 $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
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);
1507 show_result('SKIP', $tested, $tested_file, '', $temp_filenames);
1510 if (isset($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]]>");
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];
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;
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);
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 (
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 (
1605 'info' => "$bork_info [$file]",
1608 junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info);
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']);
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']);
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);
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]));
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');
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);
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]));
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');
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\"";
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";
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";
1762 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd";
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'] . "
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);
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);
1814 if ($leak_check) { // leak check
1815 $leaked = filesize($memcheck_filename) > 0;
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 */
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]);
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'])) {
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;
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']);
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
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;
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;
1921 $wanted_re = str_replace(
1922 array('%binary_string_optional%'),
1926 $wanted_re = str_replace(
1927 array('%unicode_string_optional%'),
1931 $wanted_re = str_replace(
1932 array('%unicode\|string%', '%string\|unicode%'),
1936 $wanted_re = str_replace(
1937 array('%u\|b%', '%b\|u%'),
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");
1960 if (preg_match("/^$wanted_re\$/s", $output)) {
1962 if (!$cfg['keep']['php']) {
1963 @unlink($test_file);
1965 if (isset($old_php)) {
1969 if (!$leaked && !$failed_headers) {
1970 if (isset($section_text['XFAIL'] )) {
1972 $info = " (warn: XFAIL section but test passes)";
1974 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
1975 junit_mark_test_as('PASS', $shortname, $tested);
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)) {
1991 if (!$cfg['keep']['php']) {
1992 @unlink($test_file);
1995 if (isset($old_php)) {
1999 if (!$leaked && !$failed_headers) {
2000 if (isset($section_text['XFAIL'] )) {
2002 $info = " (warn: XFAIL section but test passes)";
2004 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
2005 junit_mark_test_as('PASS', $shortname, $tested);
2014 // Test failed so we need to report details.
2015 if ($failed_headers) {
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;
2026 $restype[] = 'LEAK';
2030 $restype[] = 'WARN';
2034 if (isset($section_text['XFAIL'])) {
2035 $restype[] = 'XFAIL';
2036 $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']);
2038 $restype[] = 'FAIL';
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");
2050 if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) {
2051 error("Cannot create test output - $output_filename");
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");
2065 if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh
2068 ", FILE_BINARY) === false) {
2069 error("Cannot create test shell script - $sh_filename");
2071 chmod($sh_filename, 0755);
2074 if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, "
2075 ---- EXPECTED OUTPUT
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 (
2091 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]",
2092 'output' => $output_filename,
2093 'diff' => $diff_filename,
2098 if (isset($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)
2112 return preg_match('/^'. $l1 . '$/s', $l2);
2114 return !strcmp($l1, $l2);
2118 function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps)
2122 while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
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);
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);
2152 } else if ($eq2 > 0) {
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);
2168 while ($idx1 < $cnt1 && $idx2 < $cnt2) {
2170 if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
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);
2180 $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++];
2182 } else if ($c2 > 0) {
2183 $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++];
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) {
2199 $diff[] = current($old1);
2200 $k1 = next($old1) ? key($old1) : null;
2201 } else if ($k2 == $l2 + 1 || $k1 === null) {
2203 $diff[] = current($old2);
2204 $k2 = next($old2) ? key($old2) : null;
2205 } else if ($k1 < $k2) {
2207 $diff[] = current($old1);
2208 $k1 = next($old1) ? key($old1) : null;
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++];
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";
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;
2261 $ini_settings[$name] = $value;
2267 function settings2params(&$ini_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\"";
2279 if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value{0} == '"') {
2280 $len = strlen($value);
2282 if ($value{$len - 1} == '"') {
2284 $value{$len - 1} = "'";
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(
2313 foreach ($test_results as $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'];
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;
2338 $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = 0;
2344 $summary .= "<pre>\n";
2347 if ($show_ext_summary) {
2349 =====================================================================
2351 ---------------------------------------------------------------------
2352 Exts skipped : ' . sprintf('%4d', $exts_skipped) . '
2353 Exts tested : ' . sprintf('%4d', $exts_tested) . '
2354 ---------------------------------------------------------------------
2359 Number of tests : ' . sprintf('%4d', $n_total) . ' ' . sprintf('%8d', $x_total);
2361 if ($sum_results['BORKED']) {
2363 Tests borked : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------';
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);
2374 Tests leaked : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked);
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 =====================================================================
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 =====================================================================
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 =====================================================================
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 =====================================================================
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;
2452 $summary .= "</pre>";
2458 function show_start($start_time)
2460 global $html_output, $html_file;
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;
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;
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;
2498 fwrite($html_file, "<tr><td colspan='3'>---> $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";
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;
2514 fwrite($html_file, "<tr><td colspan='3'>---> $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";
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)
2528 global $line_length;
2530 $str = "TEST $test_idx/$test_cnt [$shortname]\r";
2531 $line_length = strlen($str);
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";
2543 // Write over the last line to avoid random trailing chars on next echo
2544 echo str_repeat(" ", $line_length), "\r";
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)) {
2560 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']);
2561 $extra = "<a href='$url'>$extra</a>";
2563 } else if (empty($extra)) {
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>";
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>";
2583 "<td>$result</td>" .
2584 "<td>$tested</td>" .
2592 function junit_init() {
2593 // Check whether a junit log is wanted.
2594 $JUNIT = getenv('TEST_PHP_JUNIT');
2595 if (empty($JUNIT)) {
2597 } elseif (!$fp = fopen($JUNIT, 'w')) {
2598 error("Failed to open $JUNIT for writing.");
2602 'name' => 'php-src',
2608 'execution_time'=> 0,
2609 'suites' => array(),
2614 $GLOBALS['JUNIT'] = $JUNIT;
2617 function junit_save_xml() {
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 = '') {
2631 $suite = $suite_name ? $JUNIT['suites'][$suite_name] : $JUNIT;
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;
2655 function junit_enabled() {
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
2669 function junit_mark_test_as($type, $file_name, $test_name, $time = null, $message = '', $details = '') {
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);
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";
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) {
2716 $JUNIT[$param] += $value;
2717 $JUNIT['suites'][$suite][$param] += $value;
2720 function junit_get_timer($file_name) {
2722 if (!junit_enabled()) return 0;
2724 if (isset($JUNIT['files'][$file_name]['total'])) {
2725 return number_format($JUNIT['files'][$file_name]['total'], 4);
2731 function junit_start_timer($file_name) {
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) {
2750 return $JUNIT['name'] . '.' . str_replace(DIRECTORY_SEPARATOR, '.', $file_name);
2753 function junit_init_suite($suite_name) {
2755 if (!junit_enabled()) return;
2757 if (!empty($JUNIT['suites'][$suite_name])) {
2761 $JUNIT['suites'][$suite_name] = array(
2762 'name' => $suite_name,
2768 'suites' => array(),
2770 'execution_time'=> 0,
2774 function junit_finish_timer($file_name) {
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']);
2796 * vim: noet sw=4 ts=4