From 07c3dbdc8c5f5b5b66ff475528cfde28dc84e209 Mon Sep 17 00:00:00 2001 From: Jani Taskinen Date: Sat, 1 Nov 2008 22:42:38 +0000 Subject: [PATCH] MF53: Sync with HEAD and PHP_5_3 --- run-tests.php | 1248 ++++++++++++++++++++++++++++++------------------- 1 file changed, 758 insertions(+), 490 deletions(-) diff --git a/run-tests.php b/run-tests.php index 7ca17d23b4..2b0dfc0f75 100755 --- a/run-tests.php +++ b/run-tests.php @@ -2,7 +2,7 @@ '; +PHP_SAPI : " , PHP_SAPI , " +PHP_VERSION : " , phpversion() , " +ZEND_VERSION: " , zend_version() , " +PHP_OS : " , PHP_OS , " - " , php_uname() , " +INI actual : " , realpath(get_cfg_var("cfg_file_path")) , " +More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n","", php_ini_scanned_files()) : "** not determined **"); ?>'; save_text($info_file, $php_info); $info_params = array(); - settings2array($ini_overwrites,$info_params); + settings2array($ini_overwrites, $info_params); settings2params($info_params); $php_info = `$php $pass_options $info_params "$info_file"`; + define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`); + if ($php_cgi && $php != $php_cgi) { $php_info_cgi = `$php_cgi $pass_options $info_params -q "$info_file"`; $php_info_sep = "\n---------------------------------------------------------------------"; @@ -223,11 +240,11 @@ More .INIs : " . (function_exists(\'php_ini_scanned_files\') ? str_replace("\n" } else { $php_cgi_info = ''; } + @unlink($info_file); - define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`); // load list of enabled extensions - save_text($info_file, ''); + save_text($info_file, ''); $exts_to_test = explode(',',`$php $pass_options $info_params "$info_file"`); // check for extensions that need special handling and regenerate $info_params_ex = array( @@ -235,12 +252,15 @@ More .INIs : " . (function_exists(\'php_ini_scanned_files\') ? str_replace("\n" 'tidy' => array('tidy.clean_output=0'), 'zlib' => array('zlib.output_compression=Off'), 'xdebug' => array('xdebug.default_enable=0'), + 'mbstring' => array('mbstring.func_overload=0'), ); + foreach($info_params_ex as $ext => $ini_overwrites_ex) { if (in_array($ext, $exts_to_test)) { $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex); } } + @unlink($info_file); // Write test context information. @@ -253,16 +273,146 @@ Extra dirs : "; echo "{$test_dir}\n "; } echo " +VALGRIND : " . ($leak_check ? $valgrind_header : 'Not used') . " ===================================================================== "; } +define('PHP_QA_EMAIL', 'qa-reports@lists.php.net'); +define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php'); + +function save_or_mail_results() +{ + global $sum_results, $just_save_results, $failed_test_summary, + $PHP_FAILED_TESTS, $CUR_DIR, $php, $output_file, $compression; + + /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */ + if (!getenv('NO_INTERACTION')) { + $fp = fopen("php://stdin", "r+"); + if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED'] || $sum_results['XFAILED']) { + echo "\nYou may have found a problem in PHP."; + } + echo "\nWe would like to send this report automatically to the\n"; + echo "PHP QA team, to give us a better understanding of how\nthe test cases are doing. If you don't want to send it\n"; + echo "immediately, you can choose \"s\" to save the report to\na file that you can send us later.\n"; + echo "Do you want to send this report now? [Yns]: "; + flush(); + + $user_input = fgets($fp, 10); + $just_save_results = (strtolower($user_input[0]) == 's'); + } + + if ($just_save_results || !getenv('NO_INTERACTION')) { + if ($just_save_results || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') { + /* + * Collect information about the host system for our report + * Fetch phpinfo() output so that we can see the PHP enviroment + * Make an archive of all the failed tests + * Send an email + */ + if ($just_save_results) { + $user_input = 's'; + } + + /* Ask the user to provide an email address, so that QA team can contact the user */ + if (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) { + 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): "; + flush(); + $user_email = trim(fgets($fp, 1024)); + $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email)); + } + + $failed_tests_data = ''; + $sep = "\n" . str_repeat('=', 80) . "\n"; + $failed_tests_data .= $failed_test_summary . "\n"; + $failed_tests_data .= get_summary(true, false) . "\n"; + + if ($sum_results['FAILED']) { + foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) { + $failed_tests_data .= $sep . $test_info['name'] . $test_info['info']; + $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output'])); + $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff'])); + $failed_tests_data .= $sep . "\n\n"; + } + $status = "failed"; + } else { + $status = "success"; + } + + $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep; + $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n"; + $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A'; + + if (substr(PHP_OS, 0, 3) != "WIN") { + /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */ + if (getenv('PHP_AUTOCONF')) { + $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version'); + } else { + $autoconf = shell_exec('autoconf --version'); + } + + /* Always use the generated libtool - Mac OSX uses 'glibtool' */ + $libtool = shell_exec($CUR_DIR . '/libtool --version'); + + /* Use shtool to find out if there is glibtool present (MacOSX) */ + $sys_libtool_path = shell_exec(realpath(dirname(__FILE__)) . '/build/shtool path glibtool libtool'); + + if ($sys_libtool_path) { + $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version'); + } + + /* Try the most common flags for 'version' */ + $flags = array('-v', '-V', '--version'); + $cc_status = 0; + + foreach($flags AS $flag) { + system(getenv('CC') . " $flag >/dev/null 2>&1", $cc_status); + if ($cc_status == 0) { + $compiler = shell_exec(getenv('CC') . " $flag 2>&1"); + break; + } + } + + $ldd = shell_exec("ldd $php 2>/dev/null"); + } + + $failed_tests_data .= "Autoconf:\n$autoconf\n"; + $failed_tests_data .= "Bundled Libtool:\n$libtool\n"; + $failed_tests_data .= "System Libtool:\n$sys_libtool\n"; + $failed_tests_data .= "Compiler:\n$compiler\n"; + $failed_tests_data .= "Bison:\n". shell_exec('bison --version 2>/dev/null') . "\n"; + $failed_tests_data .= "Libraries:\n$ldd\n"; + $failed_tests_data .= "\n"; + + if (isset($user_email)) { + $failed_tests_data .= "User's E-mail: " . $user_email . "\n\n"; + } + + $failed_tests_data .= $sep . "PHPINFO" . $sep; + $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null'); + + if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status)) { + file_put_contents($output_file, $failed_tests_data); + + if (!$just_save_results) { + echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n"; + } + + echo "Please send " . $output_file . " to " . PHP_QA_EMAIL . " manually, thank you.\n"; + } else { + fwrite($fp, "\nThank you for helping to make PHP better.\n"); + fclose($fp); + } + } + } +} + // Determine the tests to be run. $test_files = array(); $redir_tests = array(); $test_results = array(); -$PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array()); +$PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array(), 'XFAILED' => array()); // If parameters given assume they represent selected tests to run. $failed_tests_file= false; @@ -270,10 +420,12 @@ $pass_option_n = false; $pass_options = ''; $compression = 0; -$output_file = $CUR_DIR . '/php_test_results_' . @date('Ymd_Hi') . '.txt'; +$output_file = $CUR_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt'; + if ($compression) { $output_file = 'compress.zlib://' . $output_file . '.gz'; } + $just_save_results = false; $leak_check = false; $html_output = false; @@ -285,40 +437,67 @@ $conf_passed = null; $no_clean = false; $cfgtypes = array('show', 'keep'); -$cfgfiles = array('skip', 'php', 'clean'); +$cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp'); $cfg = array(); + foreach($cfgtypes as $type) { $cfg[$type] = array(); + foreach($cfgfiles as $file) { $cfg[$type][$file] = false; } } -if (getenv('TEST_PHP_ARGS')) -{ - if (!isset($argc) || !$argc || !isset($argv)) - { +if (getenv('TEST_PHP_ARGS')) { + + if (!isset($argc) || !$argc || !isset($argv)) { $argv = array(__FILE__); } + $argv = array_merge($argv, split(' ', getenv('TEST_PHP_ARGS'))); $argc = count($argv); } if (isset($argc) && $argc > 1) { + for ($i=1; $i<$argc; $i++) { $is_switch = false; $switch = substr($argv[$i],1,1); $repeat = substr($argv[$i],0,1) == '-'; + while ($repeat) { - $repeat = false; + if (!$is_switch) { $switch = substr($argv[$i],1,1); } + $is_switch = true; + + if ($repeat) { + foreach($cfgtypes as $type) { + if (strpos($switch, '--' . $type) === 0) { + foreach($cfgfiles as $file) { + if ($switch == '--' . $type . '-' . $file) { + $cfg[$type][$file] = true; + $is_switch = false; + break; + } + } + } + } + } + + if (!$is_switch) { + $is_switch = true; + break; + } + + $repeat = false; + switch($switch) { case 'r': case 'l': - $test_list = @file($argv[++$i]); + $test_list = file($argv[++$i]); if ($test_list) { foreach($test_list as $test) { $matches = array(); @@ -352,18 +531,21 @@ if (isset($argc) && $argc > 1) { $cfg['keep'][$file] = true; } break; - case '--keep-skip': - $cfg['keep']['skip'] = true; - break; - case '--keep-php': - $cfg['keep']['php'] = true; - break; - case '--keep-clean': - $cfg['keep']['clean'] = true; - break; //case 'l' case 'm': $leak_check = true; + $valgrind_cmd = "valgrind --version"; + $valgrind_header = system_with_timeout($valgrind_cmd); + $replace_count = 0; + if (!$valgrind_header) { + error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed."); + } else { + $valgrind_version = preg_replace("/valgrind-([0-9])\.([0-9])\.([0-9]+)(-\w+)?(\s+)/", '$1$2$3', $valgrind_header, 1, $replace_count); + if ($replace_count != 1 || !is_numeric($valgrind_version)) { + error("Valgrind returned invalid version info (\"$valgrind_header\"), cannot proceed."); + } + $valgrind_header = trim($valgrind_header); + } break; case 'n': if (!$pass_option_n) { @@ -371,12 +553,13 @@ if (isset($argc) && $argc > 1) { } $pass_option_n = true; break; - case 'N': - // this is always native - break; case '--no-clean': $no_clean = true; break; + case 'p': + $php = $argv[++$i]; + putenv("TEST_PHP_EXECUTABLE=$php"); + break; case 'q': putenv('NO_INTERACTION=1'); break; @@ -385,20 +568,14 @@ if (isset($argc) && $argc > 1) { $output_file = $argv[++$i]; $just_save_results = true; break; + case '--set-timeout': + $environment['TEST_TIMEOUT'] = $argv[++$i]; + break; case '--show-all': foreach($cfgfiles as $file) { $cfg['show'][$file] = true; } break; - case '--show-skip': - $cfg['show']['skip'] = true; - break; - case '--show-php': - $cfg['show']['php'] = true; - break; - case '--show-clean': - $cfg['show']['clean'] = true; - break; case '--temp-source': $temp_source = $argv[++$i]; break; @@ -415,6 +592,9 @@ if (isset($argc) && $argc > 1) { case '--verbose': $DETAILED = true; break; + case 'x': + $environment['SKIP_SLOW_TESTS'] = 1; + break; //case 'w' case '-': // repeat check with full switch @@ -424,18 +604,13 @@ if (isset($argc) && $argc > 1) { } break; case '--html': - $html_file = @fopen($argv[++$i], 'wt'); + $html_file = fopen($argv[++$i], 'wt'); $html_output = is_resource($html_file); break; case '--version': - echo '$Revision$'."\n"; + echo '$Revision$' . "\n"; exit(1); - case 'u': - case 'U': - // Allow using u or U for forward compatibility - break; - default: echo "Illegal switch '$switch' specified!\n"; case 'h': @@ -446,8 +621,8 @@ Synopsis: php run-tests.php [options] [files] [directories] Options: - -l Read the testfiles to be executed from . After the test - has finished all failed tests are written to the same . + -l Read the testfiles to be executed from . After the test + has finished all failed tests are written to the same . If the list is empty and no further test is specified then all tests are executed (same as: -r -w ). @@ -465,13 +640,15 @@ Options: with value 'bar'). -m Test for memory leaks with Valgrind. - - -N Always set (Test with unicode_semantics set off in PHP 6). - - -s Write output to . + + -p Specify PHP executable to run. -q Quiet, no user interaction (same as environment NO_INTERACTION). + -s Write output to . + + -x Sets 'SKIP_SLOW_TESTS' environmental variable. + --verbose -v Verbose mode. @@ -479,21 +656,30 @@ Options: -h This Help. --html Generate HTML output. - + --temp-source --temp-target [--temp-urlbase ] - Write temporary files to by replacing from the - filenames to generate with . If --html is being used and + Write temporary files to by replacing from the + filenames to generate with . If --html is being used and given then the generated links are relative and prefixed with the given url. In general you want to make the path - to your source files and some pach in your web page + to your source files and some pach in your web page hierarchy with pointing to . --keep-[all|php|skip|clean] - Do not delete 'all' files, 'php' test file, 'skip' or 'clean' + Do not delete 'all' files, 'php' test file, 'skip' or 'clean' file. - --show-[all|php|skip|clean] - Show 'all' files, 'php' test file, 'skip' or 'clean' file. + --set-timeout [n] + Set timeout for individual tests, where [n] is the number of + seconds. The default value is 60 seconds, or 300 seconds when + testing for memory leaks. + + --show-[all|php|skip|clean|exp|diff|out] + Show 'all' files, 'php' test file, 'skip' or 'clean' file. You + can also use this to show the output 'out', the expected result + 'exp' or the difference between them 'diff'. The result types + get written independent of the log format, however 'diff' only + exists when a test fails. --no-clean Do not execute clean section if any. @@ -501,9 +687,12 @@ HELP; exit(1); } } + if (!$is_switch) { $testfile = realpath($argv[$i]); + if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) { + if (preg_match("/\.phpt$/", $argv[$i])) { $pattern_match = glob($argv[$i]); } else if (preg_match("/\*$/", $argv[$i])) { @@ -511,9 +700,11 @@ HELP; } else { die("bogus test name " . $argv[$i] . "\n"); } + if (is_array($pattern_match)) { $test_files = array_merge($test_files, $pattern_match); } + } else if (is_dir($testfile)) { find_files($testfile); } else if (preg_match("/\.phpt$/", $testfile)) { @@ -523,33 +714,46 @@ HELP; } } } - if (strlen($conf_passed)) - { - $pass_options .= " -c '$conf_passed'"; + + if (strlen($conf_passed)) { + if (substr(PHP_OS, 0, 3) == "WIN") { + $pass_options .= " -c " . escapeshellarg($conf_passed); + } else { + $pass_options .= " -c '$conf_passed'"; + } } + $test_files = array_unique($test_files); $test_files = array_merge($test_files, $redir_tests); // Run selected tests. $test_cnt = count($test_files); + if ($test_cnt) { + putenv('NO_INTERACTION=1'); + verify_config(); write_information($html_output); usort($test_files, "test_sort"); $start_time = time(); + if (!$html_output) { echo "Running selected tests.\n"; } else { show_start($start_time); } + $test_idx = 0; run_all_tests($test_files, $environment); $end_time = time(); + if ($html_output) { show_end($end_time); } + if ($failed_tests_file) { fclose($failed_tests_file); } + if (count($test_files) || count($test_results)) { compute_summary(); if ($html_output) { @@ -558,16 +762,24 @@ HELP; echo "====================================================================="; echo get_summary(false, false); } + if ($html_output) { fclose($html_file); } + + if ($output_file != '' && $just_save_results) { + save_or_mail_results(); + } + if (getenv('REPORT_EXIT_STATUS') == 1 and preg_match('/FAILED(?: |$)/', implode(' ', $test_results))) { exit(1); } + exit(0); } } +verify_config(); write_information($html_output); // Compile a list of all test files (*.phpt). @@ -578,6 +790,7 @@ $ignored_by_ext = 0; sort($exts_to_test); $test_dirs = array(); $optionals = array('tests', 'ext', 'Zend', 'ZendEngine2', 'sapi/cli', 'sapi/cgi'); + foreach($optionals as $dir) { if (@filetype($dir) == 'dir') { $test_dirs[] = $dir; @@ -597,18 +810,20 @@ foreach ($user_tests as $dir) { find_files($dir, ($dir == 'ext')); } -function find_files($dir,$is_ext_dir=FALSE,$ignore=FALSE) +function find_files($dir, $is_ext_dir = false, $ignore = false) { global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped, $exts_tested; $o = opendir($dir) or error("cannot open directory: $dir"); - while (($name = readdir($o)) !== FALSE) { + + while (($name = readdir($o)) !== false) { + if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', 'CVS'))) { $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test)); if ($skip_ext) { $exts_skipped++; } - find_files("{$dir}/{$name}", FALSE, $ignore || $skip_ext); + find_files("{$dir}/{$name}", false, $ignore || $skip_ext); } // Cleanup any left-over tmp files from last run. @@ -627,6 +842,7 @@ function find_files($dir,$is_ext_dir=FALSE,$ignore=FALSE) } } } + closedir($o); } @@ -642,12 +858,13 @@ function test_name($name) function test_sort($a, $b) { global $cwd; - + $a = test_name($a); $b = test_name($b); - $ta = strpos($a, "{$cwd}/tests")===0 ? 1 + (strpos($a, "{$cwd}/tests/run-test")===0 ? 1 : 0) : 0; - $tb = strpos($b, "{$cwd}/tests")===0 ? 1 + (strpos($b, "{$cwd}/tests/run-test")===0 ? 1 : 0) : 0; + $ta = strpos($a, "{$cwd}/tests") === 0 ? 1 + (strpos($a, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0; + $tb = strpos($b, "{$cwd}/tests") === 0 ? 1 + (strpos($b, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0; + if ($ta == $tb) { return strcmp($a, $b); } else { @@ -665,6 +882,7 @@ $test_cnt = count($test_files); $test_idx = 0; run_all_tests($test_files, $environment); $end_time = time(); + if ($failed_tests_file) { fclose($failed_tests_file); } @@ -685,123 +903,7 @@ if ($html_output) { fclose($html_file); } -define('PHP_QA_EMAIL', 'qa-reports@lists.php.net'); -define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php'); - -/* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */ -if (!getenv('NO_INTERACTION')) { - $fp = fopen("php://stdin", "r+"); - if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED']) { - echo "\nYou may have found a problem in PHP."; - } - echo "\nWe would like to send this report automatically to the\n"; - echo "PHP QA team, to give us a better understanding of how\nthe test cases are doing. If you don't want to send it\n"; - echo "immediately, you can choose \"s\" to save the report to\na file that you can send us later.\n"; - echo "Do you want to send this report now? [Yns]: "; - flush(); - $user_input = fgets($fp, 10); - $just_save_results = (strtolower($user_input[0]) == 's'); -} -if ($just_save_results || !getenv('NO_INTERACTION')) { - if ($just_save_results || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') { - /* - * Collect information about the host system for our report - * Fetch phpinfo() output so that we can see the PHP enviroment - * Make an archive of all the failed tests - * Send an email - */ - if ($just_save_results) - { - $user_input = 's'; - } - /* Ask the user to provide an email address, so that QA team can contact the user */ - if (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) { - 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): "; - flush(); - $user_email = trim(fgets($fp, 1024)); - $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email)); - } - - $failed_tests_data = ''; - $sep = "\n" . str_repeat('=', 80) . "\n"; - - $failed_tests_data .= $failed_test_summary . "\n"; - $failed_tests_data .= get_summary(true, false) . "\n"; - - if ($sum_results['FAILED']) { - foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) { - $failed_tests_data .= $sep . $test_info['name'] . $test_info['info']; - $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output'])); - $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff'])); - $failed_tests_data .= $sep . "\n\n"; - } - $status = "failed"; - } else { - $status = "success"; - } - - $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep; - $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n"; - $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A'; - - if (substr(PHP_OS, 0, 3) != "WIN") { - /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */ - if (getenv('PHP_AUTOCONF')) { - $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version'); - } else { - $autoconf = shell_exec('autoconf --version'); - } - - /* Always use the generated libtool - Mac OSX uses 'glibtool' */ - $libtool = shell_exec($CUR_DIR . '/libtool --version'); - - /* Use shtool to find out if there is glibtool present (MacOSX) */ - $sys_libtool_path = shell_exec(dirname(__FILE__) . '/build/shtool path glibtool libtool'); - if ($sys_libtool_path) { - $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version'); - } - - /* Try the most common flags for 'version' */ - $flags = array('-v', '-V', '--version'); - $cc_status=0; - foreach($flags AS $flag) { - system(getenv('CC')." $flag >/dev/null 2>&1", $cc_status); - if ($cc_status == 0) { - $compiler = shell_exec(getenv('CC')." $flag 2>&1"); - break; - } - } - $ldd = shell_exec("ldd $php 2>/dev/null"); - } - $failed_tests_data .= "Autoconf:\n$autoconf\n"; - $failed_tests_data .= "Bundled Libtool:\n$libtool\n"; - $failed_tests_data .= "System Libtool:\n$sys_libtool\n"; - $failed_tests_data .= "Compiler:\n$compiler\n"; - $failed_tests_data .= "Bison:\n". @shell_exec('bison --version 2>/dev/null'). "\n"; - $failed_tests_data .= "Libraries:\n$ldd\n"; - $failed_tests_data .= "\n"; - - if (isset($user_email)) { - $failed_tests_data .= "User's E-mail: ".$user_email."\n\n"; - } - - $failed_tests_data .= $sep . "PHPINFO" . $sep; - $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null'); - - if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status)) { - file_put_contents($output_file, $failed_tests_data); - - if (!$just_save_results) { - echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n"; - } - - echo "Please send ".$output_file." to ".PHP_QA_EMAIL." manually, thank you.\n"; - } else { - fwrite($fp, "\nThank you for helping to make PHP better.\n"); - fclose($fp); - } - } -} +save_or_mail_results(); if (getenv('REPORT_EXIT_STATUS') == 1 and $sum_results['FAILED']) { exit(1); @@ -812,35 +914,39 @@ exit(0); // Send Email to QA Team // -function mail_qa_team($data, $compression, $status = FALSE) +function mail_qa_team($data, $compression, $status = false) { $url_bits = parse_url(QA_SUBMISSION_PAGE); - if (empty($url_bits['port'])) $url_bits['port'] = 80; - + + if (empty($url_bits['port'])) { + $url_bits['port'] = 80; + } + $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data))); $data_length = strlen($data); - + $fs = fsockopen($url_bits['host'], $url_bits['port'], $errno, $errstr, 10); + if (!$fs) { - return FALSE; + return false; } $php_version = urlencode(TESTED_PHP_VERSION); echo "\nPosting to {$url_bits['host']} {$url_bits['path']}\n"; - fwrite($fs, "POST ".$url_bits['path']."?status=$status&version=$php_version HTTP/1.1\r\n"); - fwrite($fs, "Host: ".$url_bits['host']."\r\n"); + fwrite($fs, "POST " . $url_bits['path'] . "?status=$status&version=$php_version HTTP/1.1\r\n"); + fwrite($fs, "Host: " . $url_bits['host'] . "\r\n"); fwrite($fs, "User-Agent: QA Browser 0.1\r\n"); fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n"); - fwrite($fs, "Content-Length: ".$data_length."\r\n\r\n"); + fwrite($fs, "Content-Length: " . $data_length . "\r\n\r\n"); fwrite($fs, $data); fwrite($fs, "\r\n\r\n"); fclose($fs); return 1; } - - + + // // Write the given text to a temporary file, and return the filename. // @@ -850,13 +956,15 @@ function save_text($filename, $text, $filename_copy = null) global $DETAILED; if ($filename_copy && $filename_copy != $filename) { - if (@file_put_contents($filename_copy, $text) === false) { + if (file_put_contents($filename_copy, (binary) $text, FILE_BINARY) === false) { error("Cannot open file '" . $filename_copy . "' (save_text)"); } } - if (@file_put_contents($filename, $text) === false) { + + if (file_put_contents($filename, (binary) $text, FILE_BINARY) === false) { error("Cannot open file '" . $filename . "' (save_text)"); } + if (1 < $DETAILED) echo " FILE $filename {{{ $text @@ -872,15 +980,16 @@ function error_report($testname, $logname, $tested) { $testname = realpath($testname); $logname = realpath($logname); + switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) { - case 'MSVC': - echo $testname . "(1) : $tested\n"; - echo $logname . "(1) : $tested\n"; - break; - case 'EMACS': - echo $testname . ":1: $tested\n"; - echo $logname . ":1: $tested\n"; - break; + case 'MSVC': + echo $testname . "(1) : $tested\n"; + echo $logname . "(1) : $tested\n"; + break; + case 'EMACS': + echo $testname . ":1: $tested\n"; + echo $logname . ":1: $tested\n"; + break; } } @@ -888,30 +997,36 @@ function system_with_timeout($commandline, $env = null, $stdin = null) { global $leak_check; - $data = ""; - + $data = ''; + $proc = proc_open($commandline, array( 0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w') - ), $pipes, null, $env, array("suppress_errors" => true)); + ), $pipes, null, $env, array('suppress_errors' => true, 'binary_pipes' => true)); - if (!$proc) + if (!$proc) { return false; + } - if (is_string($stdin)) { - fwrite($pipes[0], $stdin); + if (!is_null($stdin)) { + fwrite($pipes[0], (binary) $stdin); } fclose($pipes[0]); + + $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60); while (true) { /* hide errors from interrupted syscalls */ $r = $pipes; $w = null; $e = null; - $n = @stream_select($r, $w, $e, $leak_check ? 300 : 60); - if ($n === 0) { + $n = @stream_select($r, $w, $e, $timeout); + + if ($n === false) { + break; + } else if ($n === 0) { /* timed out */ $data .= "\n ** ERROR: process timed out **\n"; proc_terminate($proc); @@ -922,52 +1037,68 @@ function system_with_timeout($commandline, $env = null, $stdin = null) /* EOF */ break; } - $data .= $line; + $data .= (binary) $line; } } + $stat = proc_get_status($proc); + if ($stat['signaled']) { - $data .= "\nTermsig=".$stat['stopsig']; + $data .= "\nTermsig=" . $stat['stopsig']; } + $code = proc_close($proc); return $data; } -function run_all_tests($test_files, $env, $redir_tested = NULL) +function run_all_tests($test_files, $env, $redir_tested = null) { global $test_results, $failed_tests_file, $php, $test_cnt, $test_idx; - foreach($test_files as $name) - { - if (is_array($name)) - { + foreach($test_files as $name) { + + if (is_array($name)) { $index = "# $name[1]: $name[0]"; - if ($redir_tested) - { + + if ($redir_tested) { $name = $name[0]; } - } - else if ($redir_tested) - { + } else if ($redir_tested) { $index = "# $redir_tested: $name"; - } - else - { + } else { $index = $name; } $test_idx++; $result = run_test($php, $name, $env); - if (!is_array($name) && $result != 'REDIR') - { + + if (!is_array($name) && $result != 'REDIR') { $test_results[$index] = $result; - if ($failed_tests_file && ($result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) - { + if ($failed_tests_file && ($result == 'XFAILED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) { fwrite($failed_tests_file, "$index\n"); } } } } +// +// Show file or result block +// +function show_file_block($file, $block, $section = null) +{ + global $cfg; + + if ($cfg['show'][$file]) { + + if (is_null($section)) { + $section = strtoupper($file); + } + + echo "\n========" . $section . "========\n"; + echo rtrim($block); + echo "\n========DONE========\n"; + } +} + // // Run an individual test case. // @@ -986,7 +1117,9 @@ function run_test($php, $file, $env) $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE']; } - if (is_array($file)) $file = $file[0]; + if (is_array($file)) { + $file = $file[0]; + } if ($DETAILED) echo " ================= @@ -994,104 +1127,118 @@ TEST $file "; // Load the sections of the test file. - $section_text = array( - 'TEST' => '', - 'SKIPIF' => '', - 'GET' => '', - 'COOKIE' => '', - 'POST_RAW' => '', - 'POST' => '', - 'UPLOAD' => '', - 'ARGS' => '', - ); + $section_text = array('TEST' => ''); $fp = fopen($file, "rt") or error("Cannot open test file: $file"); $borked = false; $bork_info = ''; + if (!feof($fp)) { $line = fgets($fp); + + if ($line === false) { + $bork_info = "cannot read test"; + $borked = true; + } } else { $bork_info = "empty test [$file]"; $borked = true; } - if (strncmp('--TEST--', $line, 8)) { + if (!$borked && strncmp('--TEST--', $line, 8)) { $bork_info = "tests must start with --TEST-- [$file]"; $borked = true; } + $section = 'TEST'; $secfile = false; $secdone = false; + while (!feof($fp)) { $line = fgets($fp); // Match the beginning of a section. if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { $section = $r[1]; + + if (isset($section_text[$section])) { + $bork_info = "duplicated $section section"; + $borked = true; + } + $section_text[$section] = ''; $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL'; $secdone = false; continue; } - + // Add to the section text. if (!$secdone) { $section_text[$section] .= $line; } // End of actual test? - if ($secfile && preg_match('/^===DONE===$/', $line)) { + if ($secfile && preg_match('/^===DONE===\s*$/', $line)) { $secdone = true; } } // the redirect section allows a set of tests to be reused outside of // a given test dir - if (@count($section_text['REDIRECTTEST']) == 1) { - if ($IN_REDIRECT) { - $borked = true; - $bork_info = "Can't redirect a test from within a redirected test"; - } else { - $borked = false; - } - } else { - if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) { - $bork_info = "missing section --FILE--"; - $borked = true; - } - if (@count($section_text['FILEEOF']) == 1) { - $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']); - unset($section_text['FILEEOF']); - } - if (@count($section_text['FILE_EXTERNAL']) == 1) { - // don't allow tests to retrieve files from anywhere but this subdirectory - $section_text['FILE_EXTERNAL'] = dirname($file) . '/' . trim(str_replace('..', '', $section_text['FILE_EXTERNAL'])); - if (@file_exists($section_text['FILE_EXTERNAL'])) { - $section_text['FILE'] = file_get_contents($section_text['FILE_EXTERNAL']); - unset($section_text['FILE_EXTERNAL']); + if (!$borked) { + if (@count($section_text['REDIRECTTEST']) == 1) { + + if ($IN_REDIRECT) { + $borked = true; + $bork_info = "Can't redirect a test from within a redirected test"; } else { - $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']); + $borked = false; + } + + } else { + + if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) { + $bork_info = "missing section --FILE--"; + $borked = true; + } + + if (@count($section_text['FILEEOF']) == 1) { + $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']); + unset($section_text['FILEEOF']); + } + + if (@count($section_text['FILE_EXTERNAL']) == 1) { + // don't allow tests to retrieve files from anywhere but this subdirectory + $section_text['FILE_EXTERNAL'] = dirname($file) . '/' . trim(str_replace('..', '', $section_text['FILE_EXTERNAL'])); + + if (file_exists($section_text['FILE_EXTERNAL'])) { + $section_text['FILE'] = file_get_contents($section_text['FILE_EXTERNAL']); + unset($section_text['FILE_EXTERNAL']); + } else { + $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']); + $borked = true; + } + } + + if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) { + $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--"; $borked = true; } - } - if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) { - $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--"; - $borked = true; } } fclose($fp); - $shortname = str_replace($cwd.'/', '', $file); + $shortname = str_replace($cwd . '/', '', $file); $tested_file = $shortname; if ($borked) { show_result("BORK", $bork_info, $tested_file); $PHP_FAILED_TESTS['BORKED'][] = array ( - 'name' => $file, + 'name' => $file, 'test_name' => '', - 'output' => '', - 'diff' => '', - 'info' => "$bork_info [$file]", + 'output' => '', + 'diff' => '', + 'info' => "$bork_info [$file]", ); return 'BORKED'; } @@ -1102,19 +1249,19 @@ TEST $file if (!empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { if (isset($php_cgi)) { $old_php = $php; - $php = $php_cgi .' -C '; - } elseif (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) ."/php-cgi.exe")) { + $php = $php_cgi . ' -C '; + } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) { $old_php = $php; - $php = realpath(dirname($php) ."/php-cgi.exe") .' -C '; + $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C '; } else { - if (file_exists(dirname($php)."/../../sapi/cgi/php-cgi")) { + if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) { $old_php = $php; - $php = realpath(dirname($php)."/../../sapi/cgi/php-cgi") . ' -C '; + $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C '; } else if (file_exists("./sapi/cgi/php-cgi")) { $old_php = $php; $php = realpath("./sapi/cgi/php-cgi") . ' -C '; } else { - show_result("SKIP", $tested, $tested_file, "reason: CGI not available"); + show_result('SKIP', $tested, $tested_file, "reason: CGI not available"); return 'SKIPPED'; } } @@ -1127,40 +1274,44 @@ TEST $file } else { $temp_dir = $test_dir = realpath(dirname($file)); } + if ($temp_source && $temp_target) { $temp_dir = str_replace($temp_source, $temp_target, $temp_dir); } $main_file_name = basename($file,'phpt'); - $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff'; - $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log'; - $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp'; - $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out'; - $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem'; - $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php'; - $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'php'; - $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php'; - $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php'; - $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php'; - $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php'; + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; + $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; + $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; + $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.'); - $tmp_relative_file = str_replace(dirname(__FILE__).DIRECTORY_SEPARATOR, '', $test_file) . 't'; + $tmp_relative_file = str_replace(realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR, '', $test_file) . 't'; if ($temp_source && $temp_target) { $temp_skipif .= 's'; $temp_file .= 's'; $temp_clean .= 's'; - $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file).'.phps'; + $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps'; + if (!is_dir(dirname($copy_file))) { - @mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file)); + mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file)); } + if (isset($section_text['FILE'])) { save_text($copy_file, $section_text['FILE']); } + $temp_filenames = array( 'file' => $copy_file, - 'diff' => $diff_filename, + 'diff' => $diff_filename, 'log' => $log_filename, 'exp' => $exp_filename, 'out' => $output_filename, @@ -1176,7 +1327,7 @@ TEST $file $section_text['FILE'] = "# original source file: $shortname\n" . $section_text['FILE']; } - // unlink old test results + // unlink old test results @unlink($diff_filename); @unlink($log_filename); @unlink($exp_filename); @@ -1191,16 +1342,19 @@ TEST $file @unlink($test_clean); // Reset environment from any previous test. - $env['REDIRECT_STATUS']=''; - $env['QUERY_STRING']=''; - $env['PATH_TRANSLATED']=''; - $env['SCRIPT_FILENAME']=''; - $env['REQUEST_METHOD']=''; - $env['CONTENT_TYPE']=''; - $env['CONTENT_LENGTH']=''; + $env['REDIRECT_STATUS'] = ''; + $env['QUERY_STRING'] = ''; + $env['PATH_TRANSLATED'] = ''; + $env['SCRIPT_FILENAME'] = ''; + $env['REQUEST_METHOD'] = ''; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + if (!empty($section_text['ENV'])) { + foreach(explode("\n", trim($section_text['ENV'])) as $e) { - $e = explode('=',trim($e),2); + $e = explode('=', trim($e), 2); + if (!empty($e[0]) && isset($e[1])) { $env[$e[0]] = $e[1]; } @@ -1221,18 +1375,17 @@ TEST $file } settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings); } + settings2params($ini_settings); // Check if test should be skipped. $info = ''; $warn = false; + if (array_key_exists('SKIPIF', $section_text)) { + if (trim($section_text['SKIPIF'])) { - if ($cfg['show']['skip']) { - echo "\n========SKIP========\n"; - echo $section_text['SKIPIF']; - echo "========DONE========\n"; - } + show_file_block('skip', $section_text['SKIPIF']); save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif); $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": ""; @@ -1242,29 +1395,38 @@ TEST $file } else { $env['USE_ZEND_ALLOC'] = '1'; } + $output = system_with_timeout("$extra $php $pass_options -q $ini_settings $test_skipif", $env); + if (!$cfg['keep']['skip']) { @unlink($test_skipif); } + if (!strncasecmp('skip', ltrim($output), 4)) { + if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { - show_result("SKIP", $tested, $tested_file, "reason: $m[1]", $temp_filenames); + show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames); } else { - show_result("SKIP", $tested, $tested_file, '', $temp_filenames); + show_result('SKIP', $tested, $tested_file, '', $temp_filenames); } + if (isset($old_php)) { $php = $old_php; } + if (!$cfg['keep']['skip']) { @unlink($test_skipif); } + return 'SKIPPED'; } + if (!strncasecmp('info', ltrim($output), 4)) { if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { $info = " (info: $m[1])"; } } + if (!strncasecmp('warn', ltrim($output), 4)) { if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { $warn = true; /* only if there is a reason */ @@ -1282,17 +1444,19 @@ TEST $file $IN_REDIRECT['dir'] = realpath(dirname($file)); $IN_REDIRECT['prefix'] = trim($section_text['TEST']); - if (@count($IN_REDIRECT['TESTS']) == 1) { + if (count($IN_REDIRECT['TESTS']) == 1) { + if (is_array($org_file)) { $test_files[] = $org_file[1]; } else { $GLOBALS['test_files'] = $test_files; find_files($IN_REDIRECT['TESTS']); + foreach($GLOBALS['test_files'] as $f) { $test_files[] = array($f, $file); } } - $test_cnt += count($test_files) - 1; + $test_cnt += @count($test_files) - 1; $test_idx--; show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file); @@ -1300,16 +1464,18 @@ TEST $file // set up environment $redirenv = array_merge($environment, $IN_REDIRECT['ENV']); $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR; - + usort($test_files, "test_sort"); run_all_tests($test_files, $redirenv, $tested); - + show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file); - + // a redirected test never fails $IN_REDIRECT = false; return 'REDIR'; + } else { + $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory."; show_result("BORK", $bork_info, '', $temp_filenames); $PHP_FAILED_TESTS['BORKED'][] = array ( @@ -1318,12 +1484,16 @@ TEST $file 'output' => '', 'diff' => '', 'info' => "$bork_info [$file]", - 'unicode'=> $unicode_semantics, ); } } + if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) { - if (is_array($org_file)) $file = $org_file[0]; + + if (is_array($org_file)) { + $file = $org_file[0]; + } + $bork_info = "Redirected test did not contain redirection info"; show_result("BORK", $bork_info, '', $temp_filenames); $PHP_FAILED_TESTS['BORKED'][] = array ( @@ -1333,18 +1503,13 @@ TEST $file 'diff' => '', 'info' => "$bork_info [$file]", ); - //$test_cnt -= 1; // Only if is_array($org_file) ? - //$test_idx--; return 'BORKED'; } - + // We've satisfied the preconditions - run the test! - if ($cfg['show']['php']) { - echo "\n========TEST========\n"; - echo $section_text['FILE']; - echo "========DONE========\n"; - } + show_file_block('php', $section_text['FILE'], 'TEST'); save_text($test_file, $section_text['FILE'], $temp_file); + if (array_key_exists('GET', $section_text)) { $query_string = trim($section_text['GET']); } else { @@ -1362,20 +1527,27 @@ TEST $file $env['HTTP_COOKIE'] = ''; } - $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : ''; + $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : ''; if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { + $post = trim($section_text['POST_RAW']); $raw_lines = explode("\n", $post); $request = ''; $started = false; + foreach ($raw_lines as $line) { + if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); continue; } - if ($started) $request .= "\n"; + + if ($started) { + $request .= "\n"; + } + $started = true; $request .= $line; } @@ -1386,9 +1558,11 @@ TEST $file if (empty($request)) { return 'BORKED'; } + save_text($tmp_post, $request); $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < $tmp_post"; - } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + + } else if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { $post = trim($section_text['POST']); @@ -1420,26 +1594,14 @@ TEST $file if ($leak_check) { $env['USE_ZEND_ALLOC'] = '0'; - if (!$valgrind_version) { - $valgrind_cmd = "valgrind --version"; - $out = system_with_timeout($valgrind_cmd); - $replace_count = 0; - if (!$out) { - error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed."); - } else { - $valgrind_version = preg_replace("/valgrind-([0-9])\.([0-9])\.([0-9]+)(?:-\w+)?\s*/", '$1$2$3', $out, 1, $replace_count); - if ($replace_count != 1 || !is_numeric($valgrind_version)) { - error("Valgrind returned invalid version info (\"$out\"), cannot proceed."); - } - } - } - if ($valgrind_version < 330) { - $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd"; - } else { + if ($valgrind_version >= 330) { /* valgrind 3.3.0+ doesn't have --log-file-exactly option */ $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file=$memcheck_filename $cmd"; + } else { + $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd"; } + } else { $env['USE_ZEND_ALLOC'] = '1'; } @@ -1459,21 +1621,20 @@ COMMAND $cmd $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null); if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) { + if (trim($section_text['CLEAN'])) { - if ($cfg['show']['clean']) { - echo "\n========CLEAN=======\n"; - echo $section_text['CLEAN']; - echo "========DONE========\n"; - } + show_file_block('clean', $section_text['CLEAN']); save_text($test_clean, trim($section_text['CLEAN']), $temp_clean); + if (!$no_clean) { $clean_params = array(); - settings2array($ini_overwrites,$clean_params); + settings2array($ini_overwrites, $clean_params); settings2params($clean_params); $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": ""; system_with_timeout("$extra $php $pass_options -q $clean_params $test_clean", $env); } + if (!$cfg['keep']['clean']) { @unlink($test_clean); } @@ -1486,23 +1647,26 @@ COMMAND $cmd $passed = false; if ($leak_check) { // leak check - $leaked = @filesize($memcheck_filename) > 0; + $leaked = filesize($memcheck_filename) > 0; + if (!$leaked) { @unlink($memcheck_filename); } } // Does the output match what is expected? - $output = str_replace("\r\n", "\n", trim($out)); + $output = preg_replace("/\r\n/", "\n", trim($out)); /* when using CGI, strip the headers from the output */ $headers = ""; + if (isset($old_php) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) { $output = trim($match[2]); - $rh = preg_split("/[\n\r]+/",$match[1]); + $rh = preg_split("/[\n\r]+/", $match[1]); $headers = array(); + foreach ($rh as $line) { - if (strpos($line, ':')!==false) { + if (strpos($line, ':') !== false) { $line = explode(':', $line, 2); $headers[trim($line[0])] = trim($line[1]); } @@ -1510,10 +1674,12 @@ COMMAND $cmd } $failed_headers = false; + if (isset($section_text['EXPECTHEADERS'])) { $want = array(); $wanted_headers = array(); - $lines = preg_split("/[\n\r]+/",$section_text['EXPECTHEADERS']); + $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']); + foreach($lines as $line) { if (strpos($line, ':') !== false) { $line = explode(':', $line, 2); @@ -1521,39 +1687,53 @@ COMMAND $cmd $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]); } } + $org_headers = $headers; $headers = array(); $output_headers = array(); + foreach($want as $k => $v) { + if (isset($org_headers[$k])) { $headers = $org_headers[$k]; $output_headers[] = $k . ': ' . $org_headers[$k]; } + if (!isset($org_headers[$k]) || $org_headers[$k] != $v) { $failed_headers = true; } } + ksort($wanted_headers); $wanted_headers = join("\n", $wanted_headers); ksort($output_headers); $output_headers = join("\n", $output_headers); } + show_file_block('out', $output); + if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { + if (isset($section_text['EXPECTF'])) { $wanted = trim($section_text['EXPECTF']); } else { $wanted = trim($section_text['EXPECTREGEX']); } - $wanted_re = preg_replace('/\r\n/',"\n",$wanted); + + show_file_block('exp', $wanted); + $wanted_re = preg_replace('/\r\n/', "\n", $wanted); + if (isset($section_text['EXPECTF'])) { $wanted_re = preg_quote($wanted_re, '/'); + $wanted_re = str_replace( + array('%unicode\|string%', '%string\|unicode%'), + version_compare(PHP_VERSION, '6.0.0-dev') == -1 ? 'string' : 'unicode', + $wanted_re + ); // Stick to basics $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re); $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re); - $wanted_re = str_replace('%S', '[^\r\n]*', $wanted_re); $wanted_re = str_replace('%a', '.+', $wanted_re); - $wanted_re = str_replace('%A', '.*', $wanted_re); $wanted_re = str_replace('%w', '\s*', $wanted_re); $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re); $wanted_re = str_replace('%d', '\d+', $wanted_re); @@ -1567,7 +1747,7 @@ COMMAND $cmd print(str_repeat('=', 80) . "\n"); var_dump($output); */ - if (preg_match("/^$wanted_re\$/s", $output)) { + if (preg_match((binary) "/^$wanted_re\$/s", $output)) { $passed = true; if (!$cfg['keep']['php']) { @unlink($test_file); @@ -1580,24 +1760,32 @@ COMMAND $cmd return 'PASSED'; } } + } else { + $wanted = trim($section_text['EXPECT']); - $wanted = preg_replace('/\r\n/',"\n",$wanted); + $wanted = preg_replace('/\r\n/',"\n", $wanted); + show_file_block('exp', $wanted); + // compare and leave on success if (!strcmp($output, $wanted)) { $passed = true; + if (!$cfg['keep']['php']) { @unlink($test_file); } + if (isset($old_php)) { $php = $old_php; } + if (!$leaked && !$failed_headers) { show_result("PASS", $tested, $tested_file, '', $temp_filenames); return 'PASSED'; } } - $wanted_re = NULL; + + $wanted_re = null; } // Test failed so we need to report details. @@ -1605,6 +1793,7 @@ COMMAND $cmd $passed = false; $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted; $output = $output_headers . "\n--HEADERS--\n" . $output; + if (isset($wanted_re)) { $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re; } @@ -1613,37 +1802,46 @@ COMMAND $cmd if ($leaked) { $restype[] = 'LEAK'; } + if ($warn) { $restype[] = 'WARN'; } + if (!$passed) { - $restype[] = 'FAIL'; + if (isset($section_text['XFAIL'])) { + $restype[] = 'XFAIL'; + } else { + $restype[] = 'FAIL'; + } } if (!$passed) { + // write .exp - if (strpos($log_format,'E') !== FALSE && file_put_contents($exp_filename, $wanted) === FALSE) { + if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, (binary) $wanted, FILE_BINARY) === false) { error("Cannot create expected test output - $exp_filename"); } - + // write .out - if (strpos($log_format,'O') !== FALSE && file_put_contents($output_filename, $output) === FALSE) { + if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, (binary) $output, FILE_BINARY) === false) { error("Cannot create test output - $output_filename"); } - + // write .diff - if (strpos($log_format,'D') !== FALSE && file_put_contents($diff_filename, generate_diff($wanted,$wanted_re,$output)) === FALSE) { + $diff = generate_diff($wanted, $wanted_re, $output); + show_file_block('diff', $diff); + if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, (binary) $diff, FILE_BINARY) === false) { error("Cannot create test diff - $diff_filename"); } - + // write .log - if (strpos($log_format,'L') !== FALSE && file_put_contents($log_filename, " + if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, b" ---- EXPECTED OUTPUT $wanted ---- ACTUAL OUTPUT $output ---- FAILED -") === FALSE) { +", FILE_BINARY) === false) { error("Cannot create test log - $log_filename"); error_report($file, $log_filename, $tested); } @@ -1653,33 +1851,34 @@ $output foreach ($restype as $type) { $PHP_FAILED_TESTS[$type.'ED'][] = array ( - 'name' => $file, - 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", - 'output' => $output_filename, - 'diff' => $diff_filename, - 'info' => $info, - ); + 'name' => $file, + 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", + 'output' => $output_filename, + 'diff' => $diff_filename, + 'info' => $info, + ); } if (isset($old_php)) { $php = $old_php; } - return $restype[0].'ED'; + return $restype[0] . 'ED'; } -function comp_line($l1,$l2,$is_reg) +function comp_line($l1, $l2, $is_reg) { if ($is_reg) { - return preg_match('/^'.$l1.'$/s', $l2); + return preg_match((binary) "/^$l1$/s", (binary) $l2); } else { - return !strcmp($l1, $l2); + return !strcmp((binary) $l1, (binary) $l2); } } -function count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$idx2,$cnt1,$cnt2,$steps) +function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps) { $equal = 0; + while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { $idx1++; $idx2++; @@ -1689,95 +1888,110 @@ function count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$idx2,$cnt1,$cnt2,$steps) if (--$steps > 0) { $eq1 = 0; $st = $steps / 2; - for ($ofs1 = $idx1+1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) { - $eq = count_array_diff($ar1,$ar2,$is_reg,$w,$ofs1,$idx2,$cnt1,$cnt2,$st); + + for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) { + $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st); + if ($eq > $eq1) { $eq1 = $eq; } } + $eq2 = 0; $st = $steps; - for ($ofs2 = $idx2+1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) { - $eq = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$ofs2,$cnt1,$cnt2,$st); + + for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) { + $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st); if ($eq > $eq2) { $eq2 = $eq; } } + if ($eq1 > $eq2) { $equal += $eq1; } else if ($eq2 > 0) { $equal += $eq2; } } + return $equal; } -function generate_array_diff($ar1,$ar2,$is_reg,$w) +function generate_array_diff($ar1, $ar2, $is_reg, $w) { - $idx1 = 0; $ofs1 = 0; $cnt1 = count($ar1); - $idx2 = 0; $ofs2 = 0; $cnt2 = count($ar2); + $idx1 = 0; $ofs1 = 0; $cnt1 = @count($ar1); + $idx2 = 0; $ofs2 = 0; $cnt2 = @count($ar2); $diff = array(); $old1 = array(); $old2 = array(); - + while ($idx1 < $cnt1 && $idx2 < $cnt2) { + if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { $idx1++; $idx2++; continue; } else { - $c1 = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1+1,$idx2,$cnt1,$cnt2,10); - $c2 = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$idx2+1,$cnt1,$cnt2,10); + + $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1+1, $idx2, $cnt1, $cnt2, 10); + $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2+1, $cnt1, $cnt2, 10); + if ($c1 > $c2) { - $old1[$idx1] = sprintf("%03d- ", $idx1+1).$w[$idx1++]; + $old1[$idx1] = (binary) sprintf("%03d- ", $idx1+1) . $w[$idx1++]; $last = 1; } else if ($c2 > 0) { - $old2[$idx2] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++]; + $old2[$idx2] = (binary) sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++]; $last = 2; } else { - $old1[$idx1] = sprintf("%03d- ", $idx1+1).$w[$idx1++]; - $old2[$idx2] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++]; + $old1[$idx1] = (binary) sprintf("%03d- ", $idx1+1) . $w[$idx1++]; + $old2[$idx2] = (binary) sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++]; } } } - + reset($old1); $k1 = key($old1); $l1 = -2; - reset($old2); $k2 = key($old2); $l2 = -2; - while ($k1 !== NULL || $k2 !== NULL) { - if ($k1 == $l1+1 || $k2 === NULL) { + reset($old2); $k2 = key($old2); $l2 = -2; + + while ($k1 !== null || $k2 !== null) { + + if ($k1 == $l1 + 1 || $k2 === null) { $l1 = $k1; $diff[] = current($old1); - $k1 = next($old1) ? key($old1) : NULL; - } else if ($k2 == $l2+1 || $k1 === NULL) { + $k1 = next($old1) ? key($old1) : null; + } else if ($k2 == $l2 + 1 || $k1 === null) { $l2 = $k2; $diff[] = current($old2); - $k2 = next($old2) ? key($old2) : NULL; + $k2 = next($old2) ? key($old2) : null; } else if ($k1 < $k2) { $l1 = $k1; $diff[] = current($old1); - $k1 = next($old1) ? key($old1) : NULL; + $k1 = next($old1) ? key($old1) : null; } else { $l2 = $k2; $diff[] = current($old2); - $k2 = next($old2) ? key($old2) : NULL; + $k2 = next($old2) ? key($old2) : null; } } + while ($idx1 < $cnt1) { - $diff[] = sprintf("%03d- ", $idx1+1).$w[$idx1++]; + $diff[] = (binary) sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; } + while ($idx2 < $cnt2) { - $diff[] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++]; + $diff[] = (binary) sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; } + return $diff; } -function generate_diff($wanted,$wanted_re,$output) +function generate_diff($wanted, $wanted_re, $output) { - $w = explode("\n", $wanted); - $o = explode("\n", $output); - $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re); - $diff = generate_array_diff($r,$o,!is_null($wanted_re),$w); - return implode("\r\n", $diff); + $w = explode(b"\n", $wanted); + $o = explode(b"\n", $output); + $r = is_null($wanted_re) ? $w : explode(b"\n", $wanted_re); + $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w); + + return implode(b"\r\n", $diff); } function error($message) @@ -1789,15 +2003,20 @@ function error($message) function settings2array($settings, &$ini_settings) { foreach($settings as $setting) { - if (strpos($setting, '=')!==false) { + + if (strpos($setting, '=') !== false) { $setting = explode("=", $setting, 2); $name = trim(strtolower($setting[0])); $value = trim($setting[1]); + if ($name == 'extension') { + if (!isset($ini_settings[$name])) { $ini_settings[$name] = array(); } + $ini_settings[$name][] = $value; + } else { $ini_settings[$name] = $value; } @@ -1808,7 +2027,9 @@ function settings2array($settings, &$ini_settings) function settings2params(&$ini_settings) { $settings = ''; + foreach($ini_settings as $name => $value) { + if (is_array($value)) { foreach($value as $val) { $val = addslashes($val); @@ -1819,6 +2040,7 @@ function settings2params(&$ini_settings) $settings .= " -d \"$name=$value\""; } } + $ini_settings = $settings; } @@ -1828,13 +2050,24 @@ function compute_summary() $n_total = count($test_results); $n_total += $ignored_by_ext; - $sum_results = array('PASSED'=>0, 'WARNED'=>0, 'SKIPPED'=>0, 'FAILED'=>0, 'BORKED'=>0, 'LEAKED'=>0); + $sum_results = array( + 'PASSED' => 0, + 'WARNED' => 0, + 'SKIPPED' => 0, + 'FAILED' => 0, + 'BORKED' => 0, + 'LEAKED' => 0, + 'XFAILED' => 0 + ); + foreach ($test_results as $v) { $sum_results[$v]++; } + $sum_results['SKIPPED'] += $ignored_by_ext; $percent_results = array(); - while (list($v,$n) = each($sum_results)) { + + while (list($v, $n) = each($sum_results)) { $percent_results[$v] = (100.0 * $n) / $n_total; } } @@ -1844,89 +2077,117 @@ function get_summary($show_ext_summary, $show_html) global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $leak_check; $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED']; + if ($x_total) { $x_warned = (100.0 * $sum_results['WARNED']) / $x_total; $x_failed = (100.0 * $sum_results['FAILED']) / $x_total; + $x_xfailed = (100.0 * $sum_results['XFAILED']) / $x_total; $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total; $x_passed = (100.0 * $sum_results['PASSED']) / $x_total; } else { - $x_warned = $x_failed = $x_passed = $x_leaked = 0; + $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = 0; } - $summary = ""; - if ($show_html) $summary .= "
\n";
+	$summary = '';
+
+	if ($show_html) {
+		$summary .= "
\n";
+	}
+	
 	if ($show_ext_summary) {
-		$summary .= "
+		$summary .= '
 =====================================================================
 TEST RESULT SUMMARY
 ---------------------------------------------------------------------
-Exts skipped    : " . sprintf("%4d",$exts_skipped) . "
-Exts tested     : " . sprintf("%4d",$exts_tested) . "
+Exts skipped    : ' . sprintf('%4d', $exts_skipped) . '
+Exts tested     : ' . sprintf('%4d', $exts_tested) . '
 ---------------------------------------------------------------------
-";
+';
 	}
-	$summary .= "
-Number of tests : " . sprintf("%4d",$n_total). "          " . sprintf("%8d",$x_total);
+
+	$summary .= '
+Number of tests : ' . sprintf('%4d', $n_total) . '          ' . sprintf('%8d', $x_total);
+
 	if ($sum_results['BORKED']) {
-	$summary .= "
-Tests borked    : " . sprintf("%4d (%5.1f%%)",$sum_results['BORKED'],$percent_results['BORKED']) . " --------";
+		$summary .= '
+Tests borked    : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------';
 	}
-	$summary .= "
-Tests skipped   : " . sprintf("%4d (%5.1f%%)",$sum_results['SKIPPED'],$percent_results['SKIPPED']) . " --------
-Tests warned    : " . sprintf("%4d (%5.1f%%)",$sum_results['WARNED'], $percent_results['WARNED']) . " " . sprintf("(%5.1f%%)",$x_warned) . "
-Tests failed    : " . sprintf("%4d (%5.1f%%)",$sum_results['FAILED'], $percent_results['FAILED']) . " " . sprintf("(%5.1f%%)",$x_failed);
+
+	$summary .= '
+Tests skipped   : ' . sprintf('%4d (%5.1f%%)', $sum_results['SKIPPED'], $percent_results['SKIPPED']) . ' --------
+Tests warned    : ' . sprintf('%4d (%5.1f%%)', $sum_results['WARNED'], $percent_results['WARNED']) . ' ' . sprintf('(%5.1f%%)', $x_warned) . '
+Tests failed    : ' . sprintf('%4d (%5.1f%%)', $sum_results['FAILED'], $percent_results['FAILED']) . ' ' . sprintf('(%5.1f%%)', $x_failed) . '
+Expected fail   : ' . sprintf('%4d (%5.1f%%)', $sum_results['XFAILED'], $percent_results['XFAILED']) . ' ' . sprintf('(%5.1f%%)', $x_xfailed);
+
 	if ($leak_check) {
-		$summary .= "
-Tests leaked    : " . sprintf("%4d (%5.1f%%)",$sum_results['LEAKED'], $percent_results['LEAKED']) . " " . sprintf("(%5.1f%%)",$x_leaked);
+		$summary .= '
+Tests leaked    : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked);
 	}
-	$summary .= "
-Tests passed    : " . sprintf("%4d (%5.1f%%)",$sum_results['PASSED'], $percent_results['PASSED']) . " " . sprintf("(%5.1f%%)",$x_passed) . "
+
+	$summary .= '
+Tests passed    : ' . sprintf('%4d (%5.1f%%)', $sum_results['PASSED'], $percent_results['PASSED']) . ' ' . sprintf('(%5.1f%%)', $x_passed) . '
 ---------------------------------------------------------------------
-Time taken      : " . sprintf("%4d seconds", $end_time - $start_time) . "
+Time taken      : ' . sprintf('%4d seconds', $end_time - $start_time) . '
 =====================================================================
-";
+';
 	$failed_test_summary = '';
+
 	if (count($PHP_FAILED_TESTS['BORKED'])) {
-		$failed_test_summary .= "
+		$failed_test_summary .= '
 =====================================================================
 BORKED TEST SUMMARY
 ---------------------------------------------------------------------
-";
+';
 		foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) {
 			$failed_test_summary .= $failed_test_data['info'] . "\n";
 		}
+
 		$failed_test_summary .=  "=====================================================================\n";
 	}
-	
+
 	if (count($PHP_FAILED_TESTS['FAILED'])) {
-		$failed_test_summary .= "
+		$failed_test_summary .= '
 =====================================================================
 FAILED TEST SUMMARY
 ---------------------------------------------------------------------
-";
+';
 		foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) {
 			$failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
 		}
 		$failed_test_summary .=  "=====================================================================\n";
 	}
-	
+	if (count($PHP_FAILED_TESTS['XFAILED'])) {
+		$failed_test_summary .= '
+=====================================================================
+EXPECTED FAILED TEST SUMMARY
+---------------------------------------------------------------------
+';
+		foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) {
+			$failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
+		}
+		$failed_test_summary .=  "=====================================================================\n";
+	}
+
 	if (count($PHP_FAILED_TESTS['LEAKED'])) {
-		$failed_test_summary .= "
+		$failed_test_summary .= '
 =====================================================================
 LEAKED TEST SUMMARY
 ---------------------------------------------------------------------
-";
+';
 		foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) {
 			$failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
 		}
+
 		$failed_test_summary .=  "=====================================================================\n";
 	}
-	
+
 	if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) {
 		$summary .= $failed_test_summary;
 	}
 
-	if ($show_html) $summary .= "
"; + if ($show_html) { + $summary .= "
"; + } return $summary; } @@ -1935,34 +2196,34 @@ function show_start($start_time) { global $html_output, $html_file; - if ($html_output) - { - fwrite($html_file, "

Time Start: " . @date('Y-m-d H:i:s', $start_time) . "

\n"); + if ($html_output) { + fwrite($html_file, "

Time Start: " . date('Y-m-d H:i:s', $start_time) . "

\n"); fwrite($html_file, "\n"); } - echo "TIME START " . @date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n"; + + echo "TIME START " . date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n"; } function show_end($end_time) { global $html_output, $html_file; - if ($html_output) - { + if ($html_output) { fwrite($html_file, "
\n"); - fwrite($html_file, "

Time End: " . @date('Y-m-d H:i:s', $end_time) . "

\n"); + fwrite($html_file, "

Time End: " . date('Y-m-d H:i:s', $end_time) . "

\n"); } - echo "=====================================================================\nTIME END " . @date('Y-m-d H:i:s', $end_time) . "\n"; + + echo "=====================================================================\nTIME END " . date('Y-m-d H:i:s', $end_time) . "\n"; } function show_summary() { global $html_output, $html_file; - if ($html_output) - { + if ($html_output) { fwrite($html_file, "
\n" . get_summary(true, true)); } + echo get_summary(true, false); } @@ -1970,10 +2231,10 @@ function show_redirect_start($tests, $tested, $tested_file) { global $html_output, $html_file; - if ($html_output) - { + if ($html_output) { fwrite($html_file, "---> $tests ($tested [$tested_file]) begin\n"); } + echo "---> $tests ($tested [$tested_file]) begin\n"; } @@ -1981,10 +2242,10 @@ function show_redirect_ends($tests, $tested, $tested_file) { global $html_output, $html_file; - if ($html_output) - { + if ($html_output) { fwrite($html_file, "---> $tests ($tested [$tested_file]) done\n"); } + echo "---> $tests ($tested [$tested_file]) done\n"; } @@ -2002,33 +2263,40 @@ function show_result($result, $tested, $tested_file, $extra = '', $temp_filename echo "$result $tested [$tested_file] $extra\n"; - if ($html_output) - { - if (isset($temp_filenames['file']) && @file_exists($temp_filenames['file'])) { + if ($html_output) { + + if (isset($temp_filenames['file']) && file_exists($temp_filenames['file'])) { $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']); $tested = "$tested"; } - if (isset($temp_filenames['skip']) && @file_exists($temp_filenames['skip'])) { + + if (isset($temp_filenames['skip']) && file_exists($temp_filenames['skip'])) { + if (empty($extra)) { $extra = "skipif"; } + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']); $extra = "$extra"; + } else if (empty($extra)) { $extra = " "; } - if (isset($temp_filenames['diff']) && @file_exists($temp_filenames['diff'])) { + + if (isset($temp_filenames['diff']) && file_exists($temp_filenames['diff'])) { $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']); $diff = "diff"; } else { $diff = " "; } - if (isset($temp_filenames['mem']) && @file_exists($temp_filenames['mem'])) { + + if (isset($temp_filenames['mem']) && file_exists($temp_filenames['mem'])) { $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']); $mem = "leaks"; } else { $mem = " "; } + fwrite($html_file, "" . "$result" . -- 2.50.1