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',
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;
251 $info_file = __DIR__ . '/run-test-info.php';
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";
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);
297 // Write test context information.
299 =====================================================================
300 PHP : $php $php_info $php_cgi_info
303 foreach ($user_tests as $test_dir) {
304 echo "{$test_dir}\n ";
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]: ";
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
347 if ($just_save_results) {
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): ";
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";
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');
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');
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");
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";
437 fwrite($fp, "\nThank you for helping to make PHP better.\n");
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;
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;
465 $html_output = false;
469 $temp_urlbase = null;
473 $cfgtypes = array('show', 'keep');
474 $cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp');
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++) {
499 $switch = substr($argv[$i],1,1);
500 $repeat = substr($argv[$i],0,1) == '-';
505 $switch = substr($argv[$i],1,1);
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;
534 $test_list = file($argv[++$i]);
536 foreach($test_list as $test) {
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') {
549 // break left intentionally
551 $failed_tests_file = fopen($argv[++$i], 'w+t');
554 $failed_tests_file = fopen($argv[++$i], 'a+t');
557 $conf_passed = $argv[++$i];
560 $ini_overwrites[] = $argv[++$i];
563 $SHOW_ONLY_GROUPS = explode(",", $argv[++$i]);;
567 foreach($cfgfiles as $file) {
568 $cfg['keep'][$file] = true;
574 $valgrind_cmd = "valgrind --version";
575 $valgrind_header = system_with_timeout($valgrind_cmd, $environment);
577 if (!$valgrind_header) {
578 error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed.");
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);
588 if (!$pass_option_n) {
589 $pass_options .= ' -n';
591 $pass_option_n = true;
598 putenv("TEST_PHP_EXECUTABLE=$php");
599 $environment['TEST_PHP_EXECUTABLE'] = $php;
602 if(constant('PHP_BINARY')) {
607 putenv("TEST_PHP_EXECUTABLE=$php");
608 $environment['TEST_PHP_EXECUTABLE'] = $php;
611 putenv('NO_INTERACTION=1');
615 $output_file = $argv[++$i];
616 $just_save_results = true;
618 case '--set-timeout':
619 $environment['TEST_TIMEOUT'] = $argv[++$i];
622 foreach($cfgfiles as $file) {
623 $cfg['show'][$file] = true;
626 case '--temp-source':
627 $temp_source = $argv[++$i];
629 case '--temp-target':
630 $temp_target = $argv[++$i];
632 $temp_urlbase = $temp_target;
635 case '--temp-urlbase':
636 $temp_urlbase = $argv[++$i];
643 $environment['SKIP_SLOW_TESTS'] = 1;
646 $environment['SKIP_ONLINE_TESTS'] = 1;
650 // repeat check with full switch
652 if ($switch != '-') {
657 $html_file = fopen($argv[++$i], 'wt');
658 $html_output = is_resource($html_file);
665 echo "Illegal switch '$switch' specified!\n";
671 php run-tests.php [options] [files] [directories]
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
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.
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'
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.
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');
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;
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);
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);
790 putenv('NO_INTERACTION=1');
792 write_information($html_output);
793 usort($test_files, "test_sort");
794 $start_time = time();
797 echo "Running selected tests.\n";
799 show_start($start_time);
803 run_all_tests($test_files, $environment);
810 if ($failed_tests_file) {
811 fclose($failed_tests_file);
814 if (count($test_files) || count($test_results)) {
817 fwrite($html_file, "<hr/>\n" . get_summary(false, true));
819 echo "=====================================================================";
820 echo get_summary(false, false);
827 if ($output_file != '' && $just_save_results) {
828 save_or_mail_results();
833 if (getenv('REPORT_EXIT_STATUS') == 1 and preg_match('/FAILED(?: |$)/', implode(' ', $test_results))) {
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);
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') {
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));
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");
894 // Otherwise we're only interested in *.phpt files.
895 if (substr($name, -5) == '.phpt') {
899 $testfile = realpath("{$dir}/{$name}");
900 $test_files[] = $testfile;
908 function test_name($name)
910 if (is_array($name)) {
911 return $name[0] . ':' . $name[1];
917 function test_sort($a, $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;
928 return strcmp($a, $b);
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);
942 run_all_tests($test_files, $environment);
945 if ($failed_tests_file) {
946 fclose($failed_tests_file);
951 if (0 == count($test_results)) {
952 echo "No tests were run.\n";
965 save_or_mail_results();
969 if (getenv('REPORT_EXIT_STATUS') == 1 and $sum_results['FAILED']) {
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'])) {
989 $port = $proxy['port'];
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);
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");
1014 fwrite($fs, "\r\n\r\n");
1022 // Write the given text to a temporary file, and return the filename.
1025 function save_text($filename, $text, $filename_copy = null)
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 "
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'))) {
1057 echo $testname . "(1) : $tested\n";
1058 echo $logname . "(1) : $tested\n";
1061 echo $testname . ":1: $tested\n";
1062 echo $logname . ":1: $tested\n";
1067 function system_with_timeout($commandline, $env = null, $stdin = null)
1069 global $leak_check, $cwd;
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));
1088 if (!is_null($stdin)) {
1089 fwrite($pipes[0], $stdin);
1094 $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60);
1097 /* hide errors from interrupted syscalls */
1102 $n = @stream_select($r, $w, $e, $timeout);
1106 } else if ($n === 0) {
1108 $data .= "\n ** ERROR: process timed out **\n";
1109 proc_terminate($proc, 9);
1111 } else if ($n > 0) {
1112 $line = fread($pipes[1], 8192);
1113 if (strlen($line) == 0) {
1121 $stat = proc_get_status($proc);
1123 if ($stat['signaled']) {
1124 $data .= "\nTermsig=" . $stat['stopsig'];
1127 $code = proc_close($proc);
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) {
1143 } else if ($redir_tested) {
1144 $index = "# $redir_tested: $name";
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)
1167 if ($cfg['show'][$file]) {
1169 if (is_null($section)) {
1170 $section = strtoupper($file);
1173 echo "\n========" . $section . "========\n";
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;
1188 global $valgrind_version;
1190 $temp_filenames = null;
1193 if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) {
1194 $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
1197 if (is_array($file)) {
1201 if ($DETAILED) echo "
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");
1217 if ($line === false) {
1218 $bork_info = "cannot read test";
1222 $bork_info = "empty test [$file]";
1225 if (!$borked && strncmp('--TEST--', $line, 8)) {
1226 $bork_info = "tests must start with --TEST-- [$file]";
1234 while (!feof($fp)) {
1237 if ($line === false) {
1241 // Match the beginning of a section.
1242 if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
1244 settype($section, 'string');
1246 if (isset($section_text[$section])) {
1247 $bork_info = "duplicated $section section";
1251 $section_text[$section] = '';
1252 $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL';
1257 // Add to the section text.
1259 $section_text[$section] .= $line;
1262 // End of actual test?
1263 if ($secfile && preg_match('/^===DONE===\s*$/', $line)) {
1268 // the redirect section allows a set of tests to be reused outside of
1271 if (@count($section_text['REDIRECTTEST']) == 1) {
1275 $bork_info = "Can't redirect a test from within a redirected test";
1282 if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) {
1283 $bork_info = "missing section --FILE--";
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']);
1300 $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']);
1305 if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) {
1306 $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
1313 $shortname = str_replace($cwd . '/', '', $file);
1314 $tested_file = $shortname;
1317 show_result("BORK", $bork_info, $tested_file);
1318 $PHP_FAILED_TESTS['BORKED'][] = array (
1323 'info' => "$bork_info [$file]",
1326 junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info);
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)) {
1336 $php = $php_cgi . ' -C ';
1337 } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) {
1339 $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C ';
1341 if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) {
1343 $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C ';
1344 } else if (file_exists("./sapi/cgi/php-cgi")) {
1346 $php = realpath("./sapi/cgi/php-cgi") . ' -C ';
1347 } else if (file_exists(dirname($php) . "/php-cgi")) {
1349 $php = realpath(dirname($php) . "/php-cgi") . ' -C ';
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');
1360 show_test($test_idx, $shortname);
1362 if (is_array($IN_REDIRECT)) {
1363 $temp_dir = $test_dir = $IN_REDIRECT['dir'];
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';
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);
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'] = '';
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.
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;": "";
1499 $env['USE_ZEND_ALLOC'] = '0';
1500 $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
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);
1521 show_result('SKIP', $tested, $tested_file, '', $temp_filenames);
1524 if (isset($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);
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);
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];
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;
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);
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 (
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 (
1629 'info' => "$bork_info [$file]",
1632 junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info);
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']);
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']);
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);
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]));
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');
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);
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]));
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');
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\"";
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";
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";
1786 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd";
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'] . "
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);
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);
1838 if ($leak_check) { // leak check
1839 $leaked = filesize($memcheck_filename) > 0;
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 */
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]);
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'])) {
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;
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']);
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
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;
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;
1945 $wanted_re = str_replace(
1946 array('%binary_string_optional%'),
1950 $wanted_re = str_replace(
1951 array('%unicode_string_optional%'),
1955 $wanted_re = str_replace(
1956 array('%unicode\|string%', '%string\|unicode%'),
1960 $wanted_re = str_replace(
1961 array('%u\|b%', '%b\|u%'),
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");
1984 if (preg_match("/^$wanted_re\$/s", $output)) {
1986 if (!$cfg['keep']['php']) {
1987 @unlink($test_file);
1989 if (isset($old_php)) {
1993 if (!$leaked && !$failed_headers) {
1994 if (isset($section_text['XFAIL'] )) {
1996 $info = " (warn: XFAIL section but test passes)";
1998 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
1999 junit_mark_test_as('PASS', $shortname, $tested);
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)) {
2015 if (!$cfg['keep']['php']) {
2016 @unlink($test_file);
2019 if (isset($old_php)) {
2023 if (!$leaked && !$failed_headers) {
2024 if (isset($section_text['XFAIL'] )) {
2026 $info = " (warn: XFAIL section but test passes)";
2028 show_result("PASS", $tested, $tested_file, '', $temp_filenames);
2029 junit_mark_test_as('PASS', $shortname, $tested);
2038 // Test failed so we need to report details.
2039 if ($failed_headers) {
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;
2050 $restype[] = 'LEAK';
2054 $restype[] = 'WARN';
2058 if (isset($section_text['XFAIL'])) {
2059 $restype[] = 'XFAIL';
2060 $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']);
2062 $restype[] = 'FAIL';
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");
2074 if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) {
2075 error("Cannot create test output - $output_filename");
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");
2089 if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh
2092 ", FILE_BINARY) === false) {
2093 error("Cannot create test shell script - $sh_filename");
2095 chmod($sh_filename, 0755);
2098 if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, "
2099 ---- EXPECTED OUTPUT
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 (
2115 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]",
2116 'output' => $output_filename,
2117 'diff' => $diff_filename,
2122 if (isset($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)
2136 return preg_match('/^'. $l1 . '$/s', $l2);
2138 return !strcmp($l1, $l2);
2142 function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps)
2146 while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
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);
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);
2176 } else if ($eq2 > 0) {
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);
2192 while ($idx1 < $cnt1 && $idx2 < $cnt2) {
2194 if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
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);
2204 $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++];
2206 } else if ($c2 > 0) {
2207 $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++];
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) {
2223 $diff[] = current($old1);
2224 $k1 = next($old1) ? key($old1) : null;
2225 } else if ($k2 == $l2 + 1 || $k1 === null) {
2227 $diff[] = current($old2);
2228 $k2 = next($old2) ? key($old2) : null;
2229 } else if ($k1 < $k2) {
2231 $diff[] = current($old1);
2232 $k1 = next($old1) ? key($old1) : null;
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++];
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";
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;
2285 $ini_settings[$name] = $value;
2291 function settings2params(&$ini_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\"";
2303 if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value{0} == '"') {
2304 $len = strlen($value);
2306 if ($value{$len - 1} == '"') {
2308 $value{$len - 1} = "'";
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(
2337 foreach ($test_results as $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'];
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;
2362 $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = 0;
2368 $summary .= "<pre>\n";
2371 if ($show_ext_summary) {
2373 =====================================================================
2375 ---------------------------------------------------------------------
2376 Exts skipped : ' . sprintf('%4d', $exts_skipped) . '
2377 Exts tested : ' . sprintf('%4d', $exts_tested) . '
2378 ---------------------------------------------------------------------
2383 Number of tests : ' . sprintf('%4d', $n_total) . ' ' . sprintf('%8d', $x_total);
2385 if ($sum_results['BORKED']) {
2387 Tests borked : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------';
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);
2398 Tests leaked : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked);
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 =====================================================================
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 =====================================================================
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 =====================================================================
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 =====================================================================
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;
2476 $summary .= "</pre>";
2482 function show_start($start_time)
2484 global $html_output, $html_file;
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;
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;
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;
2522 fwrite($html_file, "<tr><td colspan='3'>---> $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";
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;
2538 fwrite($html_file, "<tr><td colspan='3'>---> $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";
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)
2552 global $line_length;
2554 $str = "TEST $test_idx/$test_cnt [$shortname]\r";
2555 $line_length = strlen($str);
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";
2567 // Write over the last line to avoid random trailing chars on next echo
2568 echo str_repeat(" ", $line_length), "\r";
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)) {
2584 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']);
2585 $extra = "<a href='$url'>$extra</a>";
2587 } else if (empty($extra)) {
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>";
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>";
2607 "<td>$result</td>" .
2608 "<td>$tested</td>" .
2616 function junit_init() {
2617 // Check whether a junit log is wanted.
2618 $JUNIT = getenv('TEST_PHP_JUNIT');
2619 if (empty($JUNIT)) {
2621 } elseif (!$fp = fopen($JUNIT, 'w')) {
2622 error("Failed to open $JUNIT for writing.");
2626 'name' => 'php-src',
2632 'execution_time'=> 0,
2633 'suites' => array(),
2638 $GLOBALS['JUNIT'] = $JUNIT;
2641 function junit_save_xml() {
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 = '') {
2655 $suite = $suite_name ? $JUNIT['suites'][$suite_name] : $JUNIT;
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;
2679 function junit_enabled() {
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
2693 function junit_mark_test_as($type, $file_name, $test_name, $time = null, $message = '', $details = '') {
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);
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";
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) {
2744 $JUNIT[$param] += $value;
2745 $JUNIT['suites'][$suite][$param] += $value;
2748 function junit_get_timer($file_name) {
2750 if (!junit_enabled()) return 0;
2752 if (isset($JUNIT['files'][$file_name]['total'])) {
2753 return number_format($JUNIT['files'][$file_name]['total'], 4);
2759 function junit_start_timer($file_name) {
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) {
2778 return $JUNIT['name'] . '.' . str_replace(DIRECTORY_SEPARATOR, '.', $file_name);
2781 function junit_init_suite($suite_name) {
2783 if (!junit_enabled()) return;
2785 if (!empty($JUNIT['suites'][$suite_name])) {
2789 $JUNIT['suites'][$suite_name] = array(
2790 'name' => $suite_name,
2796 'suites' => array(),
2798 'execution_time'=> 0,
2802 function junit_finish_timer($file_name) {
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']);
2824 * vim: noet sw=4 ts=4