diff options
Diffstat (limited to 'run-tests.php')
-rw-r--r--[-rwxr-xr-x] | run-tests.php | 360 |
1 files changed, 198 insertions, 162 deletions
diff --git a/run-tests.php b/run-tests.php index 1e07509506..6491507fc3 100755..100644 --- a/run-tests.php +++ b/run-tests.php @@ -9,7 +9,7 @@ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_01.txt | + | https://php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -26,6 +26,15 @@ /* $Id$ */ +define('INIT_DIR', getcwd()); + +// change into the PHP source directory. +if (getenv('TEST_PHP_SRCDIR')) { + @chdir(getenv('TEST_PHP_SRCDIR')); +} +define('TEST_PHP_SRCDIR', getcwd()); + + /* Sanity check to ensure that pcre extension needed by this script is available. * In the event it is not, print a nice error message indicating that this script will * not run without it. @@ -64,36 +73,23 @@ if (ini_get('date.timezone') == '') { date_default_timezone_set('UTC'); } -// store current directory -$CUR_DIR = getcwd(); - -// change into the PHP source directory. - -if (getenv('TEST_PHP_SRCDIR')) { - @chdir(getenv('TEST_PHP_SRCDIR')); -} - // Delete some security related environment variables putenv('SSH_CLIENT=deleted'); putenv('SSH_AUTH_SOCK=deleted'); putenv('SSH_TTY=deleted'); putenv('SSH_CONNECTION=deleted'); -$cwd = getcwd(); set_time_limit(0); ini_set('pcre.backtrack_limit', PHP_INT_MAX); -$valgrind_version = 0; -$valgrind_header = ''; - // delete as much output buffers as possible while(@ob_end_clean()); if (ob_get_level()) echo "Not all buffers were deleted.\n"; error_reporting(E_ALL); -$environment = isset($_ENV) ? $_ENV : array(); +$environment = $_ENV ?? array(); // Note: php.ini-development sets variables_order="GPCS" not "EGPCS", in which case $_ENV is NOT populated. // detect and handle this case, or die or warn if (empty($environment)) { @@ -132,11 +128,11 @@ if (getenv('TEST_PHP_EXECUTABLE')) { $php = getenv('TEST_PHP_EXECUTABLE'); if ($php=='auto') { - $php = $cwd . '/sapi/cli/php'; + $php = TEST_PHP_SRCDIR . '/sapi/cli/php'; putenv("TEST_PHP_EXECUTABLE=$php"); if (!getenv('TEST_PHP_CGI_EXECUTABLE')) { - $php_cgi = $cwd . '/sapi/cgi/php-cgi'; + $php_cgi = TEST_PHP_SRCDIR . '/sapi/cgi/php-cgi'; if (file_exists($php_cgi)) { putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); @@ -152,7 +148,7 @@ if (getenv('TEST_PHP_CGI_EXECUTABLE')) { $php_cgi = getenv('TEST_PHP_CGI_EXECUTABLE'); if ($php_cgi=='auto') { - $php_cgi = $cwd . '/sapi/cgi/php-cgi'; + $php_cgi = TEST_PHP_SRCDIR . '/sapi/cgi/php-cgi'; putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); } @@ -180,13 +176,27 @@ if (getenv('TEST_PHPDBG_EXECUTABLE')) { $phpdbg = getenv('TEST_PHPDBG_EXECUTABLE'); if ($phpdbg=='auto') { - $phpdbg = $cwd . '/sapi/phpdbg/phpdbg'; + $phpdbg = TEST_PHP_SRCDIR . '/sapi/phpdbg/phpdbg'; putenv("TEST_PHPDBG_EXECUTABLE=$phpdbg"); } $environment['TEST_PHPDBG_EXECUTABLE'] = $phpdbg; } +if (!function_exists("hrtime")) { + function hrtime(bool $as_num = false) + { + $t = microtime(true); + + if ($as_num) { + return $t*1000000000; + } + + $s = floor($t); + return array(0 => $s, 1 => ($t - $s)*1000000000); + } +} + function verify_config() { global $php; @@ -261,7 +271,7 @@ $no_file_cache = '-d opcache.file_cache= -d opcache.file_cache_only=0'; function write_information() { - global $cwd, $php, $php_cgi, $phpdbg, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $leak_check, $valgrind_header, $no_file_cache; + global $php, $php_cgi, $phpdbg, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $valgrind, $no_file_cache; // Get info from php $info_file = __DIR__ . '/run-test-info.php'; @@ -328,13 +338,13 @@ More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n" echo " ===================================================================== PHP : $php $php_info $php_cgi_info $phpdbg_info -CWD : $cwd +CWD : ".TEST_PHP_SRCDIR." Extra dirs : "; foreach ($user_tests as $test_dir) { echo "{$test_dir}\n "; } echo " -VALGRIND : " . ($leak_check ? $valgrind_header : 'Not used') . " +VALGRIND : " . ($valgrind ? $valgrind->getHeader() : 'Not used') . " ===================================================================== "; } @@ -347,7 +357,7 @@ define('TRAVIS_CI' , (bool) getenv('TRAVIS')); function save_or_mail_results() { global $sum_results, $just_save_results, $failed_test_summary, - $PHP_FAILED_TESTS, $CUR_DIR, $php, $output_file; + $PHP_FAILED_TESTS, $php, $output_file; /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */ if (!getenv('NO_INTERACTION') && !TRAVIS_CI) { @@ -419,7 +429,7 @@ function save_or_mail_results() } /* Always use the generated libtool - Mac OSX uses 'glibtool' */ - $libtool = shell_exec($CUR_DIR . '/libtool --version'); + $libtool = shell_exec(INIT_DIR . '/libtool --version'); /* Use shtool to find out if there is glibtool present (MacOSX) */ $sys_libtool_path = shell_exec(__DIR__ . '/build/shtool path glibtool libtool'); @@ -487,10 +497,10 @@ $failed_tests_file= false; $pass_option_n = false; $pass_options = ''; -$output_file = $CUR_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt'; +$output_file = INIT_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt'; $just_save_results = false; -$leak_check = false; +$valgrind = null; $html_output = false; $html_file = null; $temp_source = null; @@ -501,7 +511,7 @@ $no_clean = false; $slow_min_ms = INF; $cfgtypes = array('show', 'keep'); -$cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp'); +$cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp', 'mem'); $cfg = array(); foreach($cfgtypes as $type) { @@ -603,19 +613,7 @@ if (isset($argc) && $argc > 1) { break; //case 'l' case 'm': - $leak_check = true; - $valgrind_cmd = "valgrind --version"; - $valgrind_header = system_with_timeout($valgrind_cmd, $environment); - $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-(\d+)\.(\d+)\.(\d+)([.\w_-]+)?(\s+)/", '$1.$2.$3', $valgrind_header, 1, $replace_count); - if ($replace_count != 1) { - error("Valgrind returned invalid version info (\"$valgrind_header\"), cannot proceed."); - } - $valgrind_header = trim($valgrind_header); - } + $valgrind = new RuntestsValgrind($environment); break; case 'n': if (!$pass_option_n) { @@ -794,12 +792,12 @@ HELP; if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) { - if (preg_match("/\.phpt$/", $argv[$i])) { + if (substr($argv[$i], -5) == '.phpt') { $pattern_match = glob($argv[$i]); } else if (preg_match("/\*$/", $argv[$i])) { $pattern_match = glob($argv[$i] . '.phpt'); } else { - die("bogus test name " . $argv[$i] . "\n"); + die('Cannot find test file "' . $argv[$i] . '".' . PHP_EOL); } if (is_array($pattern_match)) { @@ -808,10 +806,10 @@ HELP; } else if (is_dir($testfile)) { find_files($testfile); - } else if (preg_match("/\.phpt$/", $testfile)) { + } else if (substr($testfile, -5) == '.phpt') { $test_files[] = $testfile; } else { - die("bogus test name " . $argv[$i] . "\n"); + die('Cannot find test file "' . $argv[$i] . '".' . PHP_EOL); } } } @@ -878,7 +876,7 @@ HELP; if (getenv('REPORT_EXIT_STATUS') !== '0' && getenv('REPORT_EXIT_STATUS') !== 'no' && - ($sum_results['FAILED'] || $sum_results['BORKED'])) { + ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['LEAKED'])) { exit(1); } @@ -899,7 +897,7 @@ $test_dirs = array(); $optionals = array('tests', 'ext', 'Zend', 'sapi'); foreach($optionals as $dir) { - if (@filetype($dir) == 'dir') { + if (is_dir($dir)) { $test_dirs[] = $dir; } } @@ -910,11 +908,11 @@ foreach ($exts_to_test as $key => $val) { } foreach ($test_dirs as $dir) { - find_files("{$cwd}/{$dir}", ($dir == 'ext')); + find_files(TEST_PHP_SRCDIR."/{$dir}", $dir == 'ext'); } foreach ($user_tests as $dir) { - find_files($dir, ($dir == 'ext')); + find_files($dir, $dir == 'ext'); } function find_files($dir, $is_ext_dir = false, $ignore = false) @@ -964,13 +962,11 @@ 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, TEST_PHP_SRCDIR."/tests") === 0 ? 1 + (strpos($a, TEST_PHP_SRCDIR."/tests/run-test") === 0 ? 1 : 0) : 0; + $tb = strpos($b, TEST_PHP_SRCDIR."/tests") === 0 ? 1 + (strpos($b, TEST_PHP_SRCDIR."/tests/run-test") === 0 ? 1 : 0) : 0; if ($ta == $tb) { return strcmp($a, $b); @@ -1017,10 +1013,9 @@ if ($html_output) { save_or_mail_results(); junit_save_xml(); - if (getenv('REPORT_EXIT_STATUS') !== '0' && getenv('REPORT_EXIT_STATUS') !== 'no' && - ($sum_results['FAILED'] || $sum_results['BORKED'])) { + ($sum_results['FAILED'] || $sum_results['LEAKED'])) { exit(1); } exit(0); @@ -1033,7 +1028,7 @@ function mail_qa_team($data, $status = false) { $url_bits = parse_url(QA_SUBMISSION_PAGE); - if (($proxy = getenv('http_proxy'))) { + if ($proxy = getenv('http_proxy')) { $proxy = parse_url($proxy); $path = $url_bits['host'].$url_bits['path']; $host = $proxy['host']; @@ -1120,7 +1115,7 @@ function error_report($testname, $logname, $tested) function system_with_timeout($commandline, $env = null, $stdin = null, $captureStdIn = true, $captureStdOut = true, $captureStdErr = true) { - global $leak_check, $cwd; + global $valgrind; $data = ''; @@ -1139,7 +1134,7 @@ function system_with_timeout($commandline, $env = null, $stdin = null, $captureS if ($captureStdErr) { $descriptorspec[2] = array('pipe', 'w'); } - $proc = proc_open($commandline, $descriptorspec, $pipes, $cwd, $bin_env, array('suppress_errors' => true, 'binary_pipes' => true)); + $proc = proc_open($commandline, $descriptorspec, $pipes, TEST_PHP_SRCDIR, $bin_env, array('suppress_errors' => true)); if (!$proc) { return false; @@ -1153,7 +1148,7 @@ function system_with_timeout($commandline, $env = null, $stdin = null, $captureS unset($pipes[0]); } - $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60); + $timeout = $valgrind ? 300 : ($env['TEST_TIMEOUT'] ?? 60); while (true) { /* hide errors from interrupted syscalls */ @@ -1255,11 +1250,10 @@ function show_file_block($file, $block, $section = null) // function run_test($php, $file, $env) { - global $log_format, $ini_overwrites, $cwd, $PHP_FAILED_TESTS; + global $log_format, $ini_overwrites, $PHP_FAILED_TESTS; global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx; - global $leak_check, $temp_source, $temp_target, $cfg, $environment; + global $valgrind, $temp_source, $temp_target, $cfg, $environment; global $no_clean; - global $valgrind_version; global $SHOW_ONLY_GROUPS; global $no_file_cache; global $slow_min_ms; @@ -1288,23 +1282,19 @@ TEST $file $fp = fopen($file, "rb") or error("Cannot open test file: $file"); - $borked = false; - $bork_info = ''; + $bork_info = null; 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 (!$borked && strncmp('--TEST--', $line, 8)) { + if ($bork_info === null && strncmp('--TEST--', $line, 8)) { $bork_info = "tests must start with --TEST-- [$file]"; - $borked = true; } $section = 'TEST'; @@ -1320,12 +1310,23 @@ TEST $file // Match the beginning of a section. if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { - $section = $r[1]; - settype($section, 'string'); + $section = (string) $r[1]; - if (isset($section_text[$section])) { + if (isset($section_text[$section]) && $section_text[$section]) { $bork_info = "duplicated $section section"; - $borked = true; + } + + // check for unknown sections + if (!in_array($section, array( + 'EXPECT', 'EXPECTF', 'EXPECTREGEX', 'EXPECTREGEX_EXTERNAL', 'EXPECT_EXTERNAL', 'EXPECTF_EXTERNAL', 'EXPECTHEADERS', + 'POST', 'POST_RAW', 'GZIP_POST', 'DEFLATE_POST', 'PUT', 'GET', 'COOKIE', 'ARGS', 'REQUEST', 'HEADERS', + 'FILE', 'FILEEOF', 'FILE_EXTERNAL', 'REDIRECTTEST', + 'CAPTURE_STDIO', 'STDIN', 'CGI', 'PHPDBG', + 'INI', 'ENV', 'EXTENSIONS', + 'SKIPIF', 'XFAIL', 'CLEAN', + 'CREDITS', 'DESCRIPTION', + ))) { + $bork_info = 'Unknown section "' . $section . '"'; } $section_text[$section] = ''; @@ -1347,24 +1348,20 @@ TEST $file // the redirect section allows a set of tests to be reused outside of // a given test dir - if (!$borked) { - if (@count($section_text['REDIRECTTEST']) == 1) { + if ($bork_info === null) { + if (isset($section_text['REDIRECTTEST'])) { if ($IN_REDIRECT) { - $borked = true; $bork_info = "Can't redirect a test from within a redirected test"; - } else { - $borked = false; } } else { if (!isset($section_text['PHPDBG']) && @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) { + if (isset($section_text['FILEEOF'])) { $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']); unset($section_text['FILEEOF']); } @@ -1372,7 +1369,7 @@ TEST $file foreach (array( 'FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX' ) as $prefix) { $key = $prefix . '_EXTERNAL'; - if (@count($section_text[$key]) == 1) { + if (isset($section_text[$key])) { // don't allow tests to retrieve files from anywhere but this subdirectory $section_text[$key] = dirname($file) . '/' . trim(str_replace('..', '', $section_text[$key])); @@ -1381,23 +1378,21 @@ TEST $file unset($section_text[$key]); } else { $bork_info = "could not load --" . $key . "-- " . dirname($file) . '/' . trim($section_text[$key]); - $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(TEST_PHP_SRCDIR . '/', '', $file); $tested_file = $shortname; - if ($borked) { + if ($bork_info !== null) { show_result("BORK", $bork_info, $tested_file); $PHP_FAILED_TESTS['BORKED'][] = array ( 'name' => $file, @@ -1429,22 +1424,17 @@ TEST $file $tested = trim($section_text['TEST']); /* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */ - 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'])) { + if (array_key_exists('CGI', $section_text) || !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'])) { if (isset($php_cgi)) { - $old_php = $php; $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 '; } else { if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) { - $old_php = $php; $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 if (file_exists(dirname($php) . "/php-cgi")) { - $old_php = $php; $php = realpath(dirname($php) . "/php-cgi") . ' -C '; } else { show_result('SKIP', $tested, $tested_file, "reason: CGI not available"); @@ -1464,7 +1454,6 @@ TEST $file } if (isset($phpdbg)) { - $old_php = $php; $php = $phpdbg . ' -qIb'; } else { show_result('SKIP', $tested, $tested_file, "reason: phpdbg not available"); @@ -1623,7 +1612,7 @@ TEST $file $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": ""; - if ($leak_check) { + if ($valgrind) { $env['USE_ZEND_ALLOC'] = '0'; $env['ZEND_DONT_UNLOAD_MODULES'] = 1; } else { @@ -1688,7 +1677,7 @@ TEST $file return 'SKIPPED'; } - if (@count($section_text['REDIRECTTEST']) == 1) { + if (isset($section_text['REDIRECTTEST'])) { $test_files = array(); $IN_REDIRECT = eval($section_text['REDIRECTTEST']); @@ -1918,25 +1907,11 @@ TEST $file $cmd = "$php $pass_options $ini_settings -f \"$test_file\" $args$cmdRedirect"; } - if ($leak_check) { + if ($valgrind) { $env['USE_ZEND_ALLOC'] = '0'; $env['ZEND_DONT_UNLOAD_MODULES'] = 1; - $valgrind_cmd = "valgrind -q --tool=memcheck --trace-children=yes"; - if (strpos($test_file, "pcre") !== false) { - $valgrind_cmd .= " --smc-check=all"; - } - - /* --vex-iropt-register-updates=allregs-at-mem-access is necessary for phpdbg watchpoint tests */ - if (version_compare($valgrind_version, '3.8.0', '>=')) { - /* valgrind 3.3.0+ doesn't have --log-file-exactly option */ - $cmd = "$valgrind_cmd --vex-iropt-register-updates=allregs-at-mem-access --log-file=$memcheck_filename $cmd"; - } elseif (version_compare($valgrind_version, '3.3.0', '>=')) { - $cmd = "$valgrind_cmd --vex-iropt-precise-memory-exns=yes --log-file=$memcheck_filename $cmd"; - } else { - $cmd = "$valgrind_cmd --vex-iropt-precise-memory-exns=yes --log-file-exactly=$memcheck_filename $cmd"; - } - + $cmd = $valgrind->wrapCommand($cmd, $memcheck_filename, strpos($test_file, "pcre") !== false); } else { $env['USE_ZEND_ALLOC'] = '1'; $env['ZEND_DONT_UNLOAD_MODULES'] = 0; @@ -1955,19 +1930,21 @@ COMMAND $cmd "; junit_start_timer($shortname); - $startTime = microtime(true); + $hrtime = hrtime(); + $startTime = $hrtime[0]*1000000000 + $hrtime[1]; - $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null, $captureStdIn, $captureStdOut, $captureStdErr); + $out = system_with_timeout($cmd, $env, $section_text['STDIN'] ?? null, $captureStdIn, $captureStdOut, $captureStdErr); junit_finish_timer($shortname); - $time = microtime(true) - $startTime; - if ($time * 1000 >= $slow_min_ms) { + $hrtime = hrtime(); + $time = $hrtime[0]*1000000000 + $hrtime[1] - $startTime; + if ($time >= $slow_min_ms * 1000000) { $PHP_FAILED_TESTS['SLOW'][] = array( 'name' => $file, 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", 'output' => '', 'diff' => '', - 'info' => $time, + 'info' => $time / 1000000000, ); } @@ -1997,7 +1974,7 @@ COMMAND $cmd $leaked = false; $passed = false; - if ($leak_check) { // leak check + if ($valgrind) { // leak check $leaked = filesize($memcheck_filename) > 0; if (!$leaked) { @@ -2091,35 +2068,15 @@ COMMAND $cmd $start = $end = $length; } // quote a non re portion of the string - $temp = $temp . preg_quote(substr($wanted_re, $startOffset, ($start - $startOffset)), '/'); + $temp .= preg_quote(substr($wanted_re, $startOffset, $start - $startOffset), '/'); // add the re unquoted. if ($end > $start) { - $temp = $temp . '(' . substr($wanted_re, $start+2, ($end - $start-2)). ')'; + $temp .= '(' . substr($wanted_re, $start+2, $end - $start-2). ')'; } $startOffset = $end + 2; } $wanted_re = $temp; - $wanted_re = str_replace( - array('%binary_string_optional%'), - 'string', - $wanted_re - ); - $wanted_re = str_replace( - array('%unicode_string_optional%'), - 'string', - $wanted_re - ); - $wanted_re = str_replace( - array('%unicode\|string%', '%string\|unicode%'), - 'string', - $wanted_re - ); - $wanted_re = str_replace( - array('%u\|b%', '%b\|u%'), - '', - $wanted_re - ); // Stick to basics $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re); $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re); @@ -2258,6 +2215,10 @@ $output } } + if ($valgrind && $leaked && $cfg["show"]["mem"]) { + show_file_block('mem', file_get_contents($memcheck_filename)); + } + show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames); foreach ($restype as $type) { @@ -2272,7 +2233,7 @@ $output $diff = empty($diff) ? '' : preg_replace('/\e/', '<esc>', $diff); - junit_mark_test_as($restype, str_replace($cwd . '/', '', $tested_file), $tested, null, $info, $diff); + junit_mark_test_as($restype, str_replace(TEST_PHP_SRCDIR . '/', '', $tested_file), $tested, null, $info, $diff); return $restype[0] . 'ED'; } @@ -2493,7 +2454,7 @@ function compute_summary() 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; + global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $valgrind; $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED']; @@ -2538,7 +2499,7 @@ Tests warned : ' . sprintf('%4d (%5.1f%%)', $sum_results['WARNED'], $percent_ 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) { + if ($valgrind) { $summary .= ' Tests leaked : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked); } @@ -2784,7 +2745,7 @@ function junit_init() { } else { $JUNIT = array( 'fp' => $fp, - 'name' => 'php-src', + 'name' => 'PHP', 'test_total' => 0, 'test_pass' => 0, 'test_fail' => 0, @@ -2804,8 +2765,12 @@ function junit_save_xml() { global $JUNIT; if (!junit_enabled()) return; - $xml = '<?xml version="1.0" encoding="UTF-8"?>'. PHP_EOL . - '<testsuites>' . PHP_EOL; + $xml = '<' . '?' . 'xml version="1.0" encoding="UTF-8"' . '?' . '>'. PHP_EOL; + $xml .= sprintf( + '<testsuites name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL, + $JUNIT['name'], $JUNIT['test_total'], $JUNIT['test_fail'], $JUNIT['test_error'], $JUNIT['test_skip'], + $JUNIT['execution_time'] + ); $xml .= junit_get_suite_xml(); $xml .= '</testsuites>'; fwrite($JUNIT['fp'], $xml); @@ -2814,26 +2779,23 @@ function junit_save_xml() { function junit_get_suite_xml($suite_name = '') { global $JUNIT; - $suite = $suite_name ? $JUNIT['suites'][$suite_name] : $JUNIT; + $result = ""; - $result = sprintf( - '<testsuite name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL, - $suite['name'], $suite['test_total'], $suite['test_fail'], $suite['test_error'], $suite['test_skip'], - $suite['execution_time'] - ); - - foreach($suite['suites'] as $sub_suite) { - $result .= junit_get_suite_xml($sub_suite['name']); - } + foreach ($JUNIT['suites'] as $suite_name => $suite) { + $result .= sprintf( + '<testsuite name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL, + $suite['name'], $suite['test_total'], $suite['test_fail'], $suite['test_error'], $suite['test_skip'], + $suite['execution_time'] + ); - // Output files only in subsuites - if (!empty($suite_name)) { - foreach($suite['files'] as $file) { - $result .= $JUNIT['files'][$file]['xml']; + if (!empty($suite_name)) { + foreach($suite['files'] as $file) { + $result .= $JUNIT['files'][$file]['xml']; + } } - } - $result .= '</testsuite>' . PHP_EOL; + $result .= '</testsuite>' . PHP_EOL; + } return $result; } @@ -2860,7 +2822,7 @@ function junit_mark_test_as($type, $file_name, $test_name, $time = null, $messag junit_suite_record($suite, 'test_total'); - $time = null !== $time ? $time : junit_get_timer($file_name); + $time = $time ?? junit_get_timer($file_name); junit_suite_record($suite, 'execution_time', $time); $escaped_details = htmlspecialchars($details, ENT_QUOTES, 'UTF-8'); @@ -2869,8 +2831,8 @@ function junit_mark_test_as($type, $file_name, $test_name, $time = null, $messag }, $escaped_details); $escaped_message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - $escaped_test_name = basename($file_name) . ' - ' . htmlspecialchars($test_name, ENT_QUOTES); - $JUNIT['files'][$file_name]['xml'] = "<testcase classname='$suite' name='$escaped_test_name' time='$time'>\n"; + $escaped_test_name = htmlspecialchars($test_name, ENT_QUOTES); + $JUNIT['files'][$file_name]['xml'] = "<testcase classname='" . $suite . "." . basename($file_name) . "' name='$escaped_test_name' time='$time'>\n"; if (is_array($type)) { $output_type = $type[0] . 'ED'; @@ -2940,7 +2902,33 @@ function junit_get_suitename_for($file_name) { function junit_path_to_classname($file_name) { global $JUNIT; - return $JUNIT['name'] . '.' . str_replace(DIRECTORY_SEPARATOR, '.', $file_name); + + $ret = $JUNIT['name']; + $_tmp = array(); + + // lookup whether we're in the PHP source checkout + $max = 5; + if (is_file($file_name)) { + $dir = dirname(realpath($file_name)); + } else { + $dir = realpath($file_name); + } + do { + array_unshift($_tmp, basename($dir)); + $chk = $dir . DIRECTORY_SEPARATOR . "main" . DIRECTORY_SEPARATOR . "php_version.h"; + $dir = dirname($dir); + } while (!file_exists($chk) && --$max > 0); + if (file_exists($chk)) { + if ($max) { + array_shift($_tmp); + } + foreach ($_tmp as $p) { + $ret = $ret . "." . preg_replace(",[^a-z0-9]+,i", ".", $p); + } + return $ret; + } + + return $JUNIT['name'] . '.' . str_replace(array(DIRECTORY_SEPARATOR, '-'), '.', $file_name); } function junit_init_suite($suite_name) { @@ -2981,6 +2969,54 @@ function junit_finish_timer($file_name) { unset($JUNIT['files'][$file_name]['start']); } +class RuntestsValgrind { + protected $version = ''; + protected $header = ''; + protected $version_3_3_0 = false; + protected $version_3_8_0 = false; + + public function getVersion() { + return $this->version; + } + + public function getHeader() { + return $this->header; + } + + public function __construct(array $environment) { + $header = system_with_timeout('valgrind --version', $environment); + if (!$header) { + error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed."); + } + $count = 0; + $version = preg_replace("/valgrind-(\d+)\.(\d+)\.(\d+)([.\w_-]+)?(\s+)/", '$1.$2.$3', $header, 1, $count); + if ($count != 1) { + error("Valgrind returned invalid version info (\"{$header}\"), cannot proceed."); + } + $this->version = $version; + $this->header = trim($header); + $this->version_3_3_0 = version_compare($version, '3.3.0', '>='); + $this->version_3_8_0 = version_compare($version, '3.8.0', '>='); + } + + public function wrapCommand($cmd, $memcheck_filename, $check_all) { + $vcmd = 'valgrind -q --tool=memcheck --trace-children=yes'; + if ($check_all) { + $vcmd .= ' --smc-check=all'; + } + + /* --vex-iropt-register-updates=allregs-at-mem-access is necessary for phpdbg watchpoint tests */ + if ($this->version_3_8_0) { + /* valgrind 3.3.0+ doesn't have --log-file-exactly option */ + return "$vcmd --vex-iropt-register-updates=allregs-at-mem-access --log-file=$memcheck_filename $cmd"; + } elseif ($this->version_3_3_0) { + return "$vcmd --vex-iropt-precise-memory-exns=yes --log-file=$memcheck_filename $cmd"; + } else { + return "$vcmd --vex-iropt-precise-memory-exns=yes --log-file-exactly=$memcheck_filename $cmd"; + } + } +} + /* * Local variables: * tab-width: 4 |