1#!/usr/bin/env php 2<?php 3/* 4 +----------------------------------------------------------------------+ 5 | PHP Version 5 | 6 +----------------------------------------------------------------------+ 7 | Copyright (c) 1997-2010 The PHP Group | 8 +----------------------------------------------------------------------+ 9 | This source file is subject to version 3.01 of the PHP license, | 10 | that is bundled with this package in the file LICENSE, and is | 11 | available through the world-wide-web at the following url: | 12 | http://www.php.net/license/3_01.txt | 13 | If you did not receive a copy of the PHP license and are unable to | 14 | obtain it through the world-wide-web, please send a note to | 15 | license@php.net so we can mail you a copy immediately. | 16 +----------------------------------------------------------------------+ 17 | Authors: Ilia Alshanetsky <iliaa@php.net> | 18 | Preston L. Bannister <pbannister@php.net> | 19 | Marcus Boerger <helly@php.net> | 20 | Derick Rethans <derick@php.net> | 21 | Sander Roobol <sander@php.net> | 22 | (based on version by: Stig Bakken <ssb@php.net>) | 23 | (based on the PHP 3 test framework by Rasmus Lerdorf) | 24 +----------------------------------------------------------------------+ 25 */ 26 27/* $Id: cfc562ebc15dedd268fa9aade4cc3e4350da4d42 $ */ 28 29/* Sanity check to ensure that pcre extension needed by this script is available. 30 * In the event it is not, print a nice error message indicating that this script will 31 * not run without it. 32 */ 33 34if (!extension_loaded('pcre')) { 35 echo <<<NO_PCRE_ERROR 36 37+-----------------------------------------------------------+ 38| ! ERROR ! | 39| The test-suite requires that you have pcre extension | 40| enabled. To enable this extension either compile your PHP | 41| with --with-pcre-regex or if you've compiled pcre as a | 42| shared module load it via php.ini. | 43+-----------------------------------------------------------+ 44 45NO_PCRE_ERROR; 46exit; 47} 48 49if (!function_exists('proc_open')) { 50 echo <<<NO_PROC_OPEN_ERROR 51 52+-----------------------------------------------------------+ 53| ! ERROR ! | 54| The test-suite requires that proc_open() is available. | 55| Please check if you disabled it in php.ini. | 56+-----------------------------------------------------------+ 57 58NO_PROC_OPEN_ERROR; 59exit; 60} 61 62// Version constants only available as of 5.2.8 63if (!defined("PHP_VERSION_ID")) { 64 list($major, $minor, $bug) = explode(".", phpversion(), 3); 65 $bug = (int)$bug; // Many distros make up their own versions 66 if ($bug < 10) { 67 $bug = "0$bug"; 68 } 69 70 define("PHP_VERSION_ID", "{$major}0{$minor}$bug"); 71 define("PHP_MAJOR_VERSION", $major); 72} 73 74// __DIR__ is available from 5.3.0 75if (PHP_VERSION_ID < 50300) { 76 define('__DIR__', realpath(dirname(__FILE__))); 77 // FILE_BINARY is available from 5.2.7 78 if (PHP_VERSION_ID < 50207) { 79 define('FILE_BINARY', 0); 80 } 81} 82 83// If timezone is not set, use UTC. 84if (ini_get('date.timezone') == '') { 85 date_default_timezone_set('UTC'); 86} 87 88// store current directory 89$CUR_DIR = getcwd(); 90 91// change into the PHP source directory. 92 93if (getenv('TEST_PHP_SRCDIR')) { 94 @chdir(getenv('TEST_PHP_SRCDIR')); 95} 96 97// Delete some security related environment variables 98putenv('SSH_CLIENT=deleted'); 99putenv('SSH_AUTH_SOCK=deleted'); 100putenv('SSH_TTY=deleted'); 101putenv('SSH_CONNECTION=deleted'); 102 103$cwd = getcwd(); 104set_time_limit(0); 105 106ini_set('pcre.backtrack_limit', PHP_INT_MAX); 107 108$valgrind_version = 0; 109$valgrind_header = ''; 110 111// delete as much output buffers as possible 112while(@ob_end_clean()); 113if (ob_get_level()) echo "Not all buffers were deleted.\n"; 114 115error_reporting(E_ALL); 116if (PHP_MAJOR_VERSION < 6) { 117 ini_set('magic_quotes_runtime',0); // this would break tests by modifying EXPECT sections 118 if (ini_get('safe_mode')) { 119 echo <<< SAFE_MODE_WARNING 120 121+-----------------------------------------------------------+ 122| ! WARNING ! | 123| You are running the test-suite with "safe_mode" ENABLED ! | 124| | 125| Chances are high that no test will work at all, | 126| depending on how you configured "safe_mode" ! | 127+-----------------------------------------------------------+ 128 129 130SAFE_MODE_WARNING; 131 } 132} 133 134$environment = isset($_ENV) ? $_ENV : array(); 135if ((substr(PHP_OS, 0, 3) == "WIN") && empty($environment["SystemRoot"])) { 136 $environment["SystemRoot"] = getenv("SystemRoot"); 137} 138 139// Don't ever guess at the PHP executable location. 140// Require the explicit specification. 141// Otherwise we could end up testing the wrong file! 142 143$php = null; 144$php_cgi = null; 145 146if (getenv('TEST_PHP_EXECUTABLE')) { 147 $php = getenv('TEST_PHP_EXECUTABLE'); 148 149 if ($php=='auto') { 150 $php = $cwd . '/sapi/cli/php'; 151 putenv("TEST_PHP_EXECUTABLE=$php"); 152 153 if (!getenv('TEST_PHP_CGI_EXECUTABLE')) { 154 $php_cgi = $cwd . '/sapi/cgi/php-cgi'; 155 156 if (file_exists($php_cgi)) { 157 putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); 158 } else { 159 $php_cgi = null; 160 } 161 } 162 } 163 $environment['TEST_PHP_EXECUTABLE'] = $php; 164} 165 166if (getenv('TEST_PHP_CGI_EXECUTABLE')) { 167 $php_cgi = getenv('TEST_PHP_CGI_EXECUTABLE'); 168 169 if ($php_cgi=='auto') { 170 $php_cgi = $cwd . '/sapi/cgi/php-cgi'; 171 putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); 172 } 173 174 $environment['TEST_PHP_CGI_EXECUTABLE'] = $php_cgi; 175} 176 177function verify_config() 178{ 179 global $php; 180 181 if (empty($php) || !file_exists($php)) { 182 error('environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!'); 183 } 184 185 if (function_exists('is_executable') && !is_executable($php)) { 186 error("invalid PHP executable specified by TEST_PHP_EXECUTABLE = $php"); 187 } 188} 189 190if (getenv('TEST_PHP_LOG_FORMAT')) { 191 $log_format = strtoupper(getenv('TEST_PHP_LOG_FORMAT')); 192} else { 193 $log_format = 'LEODS'; 194} 195 196// Check whether a detailed log is wanted. 197if (getenv('TEST_PHP_DETAILED')) { 198 $DETAILED = getenv('TEST_PHP_DETAILED'); 199} else { 200 $DETAILED = 0; 201} 202 203junit_init(); 204 205if (getenv('SHOW_ONLY_GROUPS')) { 206 $SHOW_ONLY_GROUPS = explode(",", getenv('SHOW_ONLY_GROUPS')); 207} else { 208 $SHOW_ONLY_GROUPS = array(); 209} 210 211// Check whether user test dirs are requested. 212if (getenv('TEST_PHP_USER')) { 213 $user_tests = explode (',', getenv('TEST_PHP_USER')); 214} else { 215 $user_tests = array(); 216} 217 218$exts_to_test = array(); 219$ini_overwrites = array( 220 'output_handler=', 221 'open_basedir=', 222 'safe_mode=0', 223 'disable_functions=', 224 'output_buffering=Off', 225 'error_reporting=' . (E_ALL | E_STRICT), 226 'display_errors=1', 227 'display_startup_errors=1', 228 'log_errors=0', 229 'html_errors=0', 230 'track_errors=1', 231 'report_memleaks=1', 232 'report_zend_debug=0', 233 'docref_root=', 234 'docref_ext=.html', 235 'error_prepend_string=', 236 'error_append_string=', 237 'auto_prepend_file=', 238 'auto_append_file=', 239 'magic_quotes_runtime=0', 240 'ignore_repeated_errors=0', 241 'precision=14', 242 'memory_limit=128M', 243 ); 244 245function write_information($show_html) 246{ 247 global $cwd, $php, $php_cgi, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $leak_check, $valgrind_header; 248 249 // Get info from php 250 $info_file = __DIR__ . '/run-test-info.php'; 251 @unlink($info_file); 252 $php_info = '<?php echo " 253PHP_SAPI : " , PHP_SAPI , " 254PHP_VERSION : " , phpversion() , " 255ZEND_VERSION: " , zend_version() , " 256PHP_OS : " , PHP_OS , " - " , php_uname() , " 257INI actual : " , realpath(get_cfg_var("cfg_file_path")) , " 258More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n","", php_ini_scanned_files()) : "** not determined **"); ?>'; 259 save_text($info_file, $php_info); 260 $info_params = array(); 261 settings2array($ini_overwrites, $info_params); 262 settings2params($info_params); 263 $php_info = `$php $pass_options $info_params "$info_file"`; 264 define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`); 265 266 if ($php_cgi && $php != $php_cgi) { 267 $php_info_cgi = `$php_cgi $pass_options $info_params -q "$info_file"`; 268 $php_info_sep = "\n---------------------------------------------------------------------"; 269 $php_cgi_info = "$php_info_sep\nPHP : $php_cgi $php_info_cgi$php_info_sep"; 270 } else { 271 $php_cgi_info = ''; 272 } 273 274 @unlink($info_file); 275 276 // load list of enabled extensions 277 save_text($info_file, '<?php echo join(",", get_loaded_extensions()); ?>'); 278 $exts_to_test = explode(',',`$php $pass_options $info_params "$info_file"`); 279 // check for extensions that need special handling and regenerate 280 $info_params_ex = array( 281 'session' => array('session.auto_start=0'), 282 'tidy' => array('tidy.clean_output=0'), 283 'zlib' => array('zlib.output_compression=Off'), 284 'xdebug' => array('xdebug.default_enable=0'), 285 'mbstring' => array('mbstring.func_overload=0'), 286 ); 287 288 foreach($info_params_ex as $ext => $ini_overwrites_ex) { 289 if (in_array($ext, $exts_to_test)) { 290 $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex); 291 } 292 } 293 294 @unlink($info_file); 295 296 // Write test context information. 297 echo " 298===================================================================== 299PHP : $php $php_info $php_cgi_info 300CWD : $cwd 301Extra dirs : "; 302 foreach ($user_tests as $test_dir) { 303 echo "{$test_dir}\n "; 304 } 305 echo " 306VALGRIND : " . ($leak_check ? $valgrind_header : 'Not used') . " 307===================================================================== 308"; 309} 310 311define('PHP_QA_EMAIL', 'qa-reports@lists.php.net'); 312define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php'); 313define('QA_REPORTS_PAGE', 'http://qa.php.net/reports'); 314 315function save_or_mail_results() 316{ 317 global $sum_results, $just_save_results, $failed_test_summary, 318 $PHP_FAILED_TESTS, $CUR_DIR, $php, $output_file, $compression; 319 320 /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */ 321 if (!getenv('NO_INTERACTION')) { 322 $fp = fopen("php://stdin", "r+"); 323 if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED'] || $sum_results['XFAILED']) { 324 echo "\nYou may have found a problem in PHP."; 325 } 326 echo "\nThis report can be automatically sent to the PHP QA team at\n"; 327 echo QA_REPORTS_PAGE . " and http://news.php.net/php.qa.reports\n"; 328 echo "This gives us a better understanding of PHP's behavior.\n"; 329 echo "If you don't want to send the report immediately you can choose\n"; 330 echo "option \"s\" to save it. You can then email it to ". PHP_QA_EMAIL . " later.\n"; 331 echo "Do you want to send this report now? [Yns]: "; 332 flush(); 333 334 $user_input = fgets($fp, 10); 335 $just_save_results = (strtolower($user_input[0]) == 's'); 336 } 337 338 if ($just_save_results || !getenv('NO_INTERACTION')) { 339 if ($just_save_results || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') { 340 /* 341 * Collect information about the host system for our report 342 * Fetch phpinfo() output so that we can see the PHP enviroment 343 * Make an archive of all the failed tests 344 * Send an email 345 */ 346 if ($just_save_results) { 347 $user_input = 's'; 348 } 349 350 /* Ask the user to provide an email address, so that QA team can contact the user */ 351 if (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) { 352 echo "\nPlease enter your email address.\n(Your address will be mangled so that it will not go out on any\nmailinglist in plain text): "; 353 flush(); 354 $user_email = trim(fgets($fp, 1024)); 355 $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email)); 356 } 357 358 $failed_tests_data = ''; 359 $sep = "\n" . str_repeat('=', 80) . "\n"; 360 $failed_tests_data .= $failed_test_summary . "\n"; 361 $failed_tests_data .= get_summary(true, false) . "\n"; 362 363 if ($sum_results['FAILED']) { 364 foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) { 365 $failed_tests_data .= $sep . $test_info['name'] . $test_info['info']; 366 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output']), FILE_BINARY); 367 $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff']), FILE_BINARY); 368 $failed_tests_data .= $sep . "\n\n"; 369 } 370 $status = "failed"; 371 } else { 372 $status = "success"; 373 } 374 375 $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep; 376 $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n"; 377 $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A'; 378 379 if (substr(PHP_OS, 0, 3) != "WIN") { 380 /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */ 381 if (getenv('PHP_AUTOCONF')) { 382 $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version'); 383 } else { 384 $autoconf = shell_exec('autoconf --version'); 385 } 386 387 /* Always use the generated libtool - Mac OSX uses 'glibtool' */ 388 $libtool = shell_exec($CUR_DIR . '/libtool --version'); 389 390 /* Use shtool to find out if there is glibtool present (MacOSX) */ 391 $sys_libtool_path = shell_exec(__DIR__ . '/build/shtool path glibtool libtool'); 392 393 if ($sys_libtool_path) { 394 $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version'); 395 } 396 397 /* Try the most common flags for 'version' */ 398 $flags = array('-v', '-V', '--version'); 399 $cc_status = 0; 400 401 foreach($flags AS $flag) { 402 system(getenv('CC') . " $flag >/dev/null 2>&1", $cc_status); 403 if ($cc_status == 0) { 404 $compiler = shell_exec(getenv('CC') . " $flag 2>&1"); 405 break; 406 } 407 } 408 409 $ldd = shell_exec("ldd $php 2>/dev/null"); 410 } 411 412 $failed_tests_data .= "Autoconf:\n$autoconf\n"; 413 $failed_tests_data .= "Bundled Libtool:\n$libtool\n"; 414 $failed_tests_data .= "System Libtool:\n$sys_libtool\n"; 415 $failed_tests_data .= "Compiler:\n$compiler\n"; 416 $failed_tests_data .= "Bison:\n". shell_exec('bison --version 2>/dev/null') . "\n"; 417 $failed_tests_data .= "Libraries:\n$ldd\n"; 418 $failed_tests_data .= "\n"; 419 420 if (isset($user_email)) { 421 $failed_tests_data .= "User's E-mail: " . $user_email . "\n\n"; 422 } 423 424 $failed_tests_data .= $sep . "PHPINFO" . $sep; 425 $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null'); 426 427 if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status)) { 428 file_put_contents($output_file, $failed_tests_data); 429 430 if (!$just_save_results) { 431 echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n"; 432 } 433 434 echo "Please send " . $output_file . " to " . PHP_QA_EMAIL . " manually, thank you.\n"; 435 } else { 436 fwrite($fp, "\nThank you for helping to make PHP better.\n"); 437 fclose($fp); 438 } 439 } 440 } 441} 442 443// Determine the tests to be run. 444 445$test_files = array(); 446$redir_tests = array(); 447$test_results = array(); 448$PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array(), 'XFAILED' => array()); 449 450// If parameters given assume they represent selected tests to run. 451$failed_tests_file= false; 452$pass_option_n = false; 453$pass_options = ''; 454 455$compression = 0; 456$output_file = $CUR_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt'; 457 458if ($compression) { 459 $output_file = 'compress.zlib://' . $output_file . '.gz'; 460} 461 462$just_save_results = false; 463$leak_check = false; 464$html_output = false; 465$html_file = null; 466$temp_source = null; 467$temp_target = null; 468$temp_urlbase = null; 469$conf_passed = null; 470$no_clean = false; 471 472$cfgtypes = array('show', 'keep'); 473$cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp'); 474$cfg = array(); 475 476foreach($cfgtypes as $type) { 477 $cfg[$type] = array(); 478 479 foreach($cfgfiles as $file) { 480 $cfg[$type][$file] = false; 481 } 482} 483 484if (getenv('TEST_PHP_ARGS')) { 485 486 if (!isset($argc) || !$argc || !isset($argv)) { 487 $argv = array(__FILE__); 488 } 489 490 $argv = array_merge($argv, explode(' ', getenv('TEST_PHP_ARGS'))); 491 $argc = count($argv); 492} 493 494if (isset($argc) && $argc > 1) { 495 496 for ($i=1; $i<$argc; $i++) { 497 $is_switch = false; 498 $switch = substr($argv[$i],1,1); 499 $repeat = substr($argv[$i],0,1) == '-'; 500 501 while ($repeat) { 502 503 if (!$is_switch) { 504 $switch = substr($argv[$i],1,1); 505 } 506 507 $is_switch = true; 508 509 if ($repeat) { 510 foreach($cfgtypes as $type) { 511 if (strpos($switch, '--' . $type) === 0) { 512 foreach($cfgfiles as $file) { 513 if ($switch == '--' . $type . '-' . $file) { 514 $cfg[$type][$file] = true; 515 $is_switch = false; 516 break; 517 } 518 } 519 } 520 } 521 } 522 523 if (!$is_switch) { 524 $is_switch = true; 525 break; 526 } 527 528 $repeat = false; 529 530 switch($switch) { 531 case 'r': 532 case 'l': 533 $test_list = file($argv[++$i]); 534 if ($test_list) { 535 foreach($test_list as $test) { 536 $matches = array(); 537 if (preg_match('/^#.*\[(.*)\]\:\s+(.*)$/', $test, $matches)) { 538 $redir_tests[] = array($matches[1], $matches[2]); 539 } else if (strlen($test)) { 540 $test_files[] = trim($test); 541 } 542 } 543 } 544 if ($switch != 'l') { 545 break; 546 } 547 $i--; 548 // break left intentionally 549 case 'w': 550 $failed_tests_file = fopen($argv[++$i], 'w+t'); 551 break; 552 case 'a': 553 $failed_tests_file = fopen($argv[++$i], 'a+t'); 554 break; 555 case 'c': 556 $conf_passed = $argv[++$i]; 557 break; 558 case 'd': 559 $ini_overwrites[] = $argv[++$i]; 560 break; 561 case 'g': 562 $SHOW_ONLY_GROUPS = explode(",", $argv[++$i]);; 563 break; 564 //case 'h' 565 case '--keep-all': 566 foreach($cfgfiles as $file) { 567 $cfg['keep'][$file] = true; 568 } 569 break; 570 //case 'l' 571 case 'm': 572 $leak_check = true; 573 $valgrind_cmd = "valgrind --version"; 574 $valgrind_header = system_with_timeout($valgrind_cmd, $environment); 575 $replace_count = 0; 576 if (!$valgrind_header) { 577 error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed."); 578 } else { 579 $valgrind_version = preg_replace("/valgrind-([0-9])\.([0-9])\.([0-9]+)([.-\w]+)?(\s+)/", '$1$2$3', $valgrind_header, 1, $replace_count); 580 if ($replace_count != 1 || !is_numeric($valgrind_version)) { 581 error("Valgrind returned invalid version info (\"$valgrind_header\"), cannot proceed."); 582 } 583 $valgrind_header = trim($valgrind_header); 584 } 585 break; 586 case 'n': 587 if (!$pass_option_n) { 588 $pass_options .= ' -n'; 589 } 590 $pass_option_n = true; 591 break; 592 case '--no-clean': 593 $no_clean = true; 594 break; 595 case 'p': 596 $php = $argv[++$i]; 597 putenv("TEST_PHP_EXECUTABLE=$php"); 598 $environment['TEST_PHP_EXECUTABLE'] = $php; 599 break; 600 case 'q': 601 putenv('NO_INTERACTION=1'); 602 break; 603 //case 'r' 604 case 's': 605 $output_file = $argv[++$i]; 606 $just_save_results = true; 607 break; 608 case '--set-timeout': 609 $environment['TEST_TIMEOUT'] = $argv[++$i]; 610 break; 611 case '--show-all': 612 foreach($cfgfiles as $file) { 613 $cfg['show'][$file] = true; 614 } 615 break; 616 case '--temp-source': 617 $temp_source = $argv[++$i]; 618 break; 619 case '--temp-target': 620 $temp_target = $argv[++$i]; 621 if ($temp_urlbase) { 622 $temp_urlbase = $temp_target; 623 } 624 break; 625 case '--temp-urlbase': 626 $temp_urlbase = $argv[++$i]; 627 break; 628 case 'v': 629 case '--verbose': 630 $DETAILED = true; 631 break; 632 case 'x': 633 $environment['SKIP_SLOW_TESTS'] = 1; 634 break; 635 //case 'w' 636 case '-': 637 // repeat check with full switch 638 $switch = $argv[$i]; 639 if ($switch != '-') { 640 $repeat = true; 641 } 642 break; 643 case '--html': 644 $html_file = fopen($argv[++$i], 'wt'); 645 $html_output = is_resource($html_file); 646 break; 647 case '--version': 648 echo '$Id: cfc562ebc15dedd268fa9aade4cc3e4350da4d42 $' . "\n"; 649 exit(1); 650 651 default: 652 echo "Illegal switch '$switch' specified!\n"; 653 case 'h': 654 case '-help': 655 case '--help': 656 echo <<<HELP 657Synopsis: 658 php run-tests.php [options] [files] [directories] 659 660Options: 661 -l <file> Read the testfiles to be executed from <file>. After the test 662 has finished all failed tests are written to the same <file>. 663 If the list is empty and no further test is specified then 664 all tests are executed (same as: -r <file> -w <file>). 665 666 -r <file> Read the testfiles to be executed from <file>. 667 668 -w <file> Write a list of all failed tests to <file>. 669 670 -a <file> Same as -w but append rather then truncating <file>. 671 672 -c <file> Look for php.ini in directory <file> or use <file> as ini. 673 674 -n Pass -n option to the php binary (Do not use a php.ini). 675 676 -d foo=bar Pass -d option to the php binary (Define INI entry foo 677 with value 'bar'). 678 679 -g Comma seperated list of groups to show during test run 680 (possible values: PASS, FAIL, XFAIL, SKIP, BORK, WARN, LEAK, REDIRECT). 681 682 -m Test for memory leaks with Valgrind. 683 684 -p <php> Specify PHP executable to run. 685 686 -q Quiet, no user interaction (same as environment NO_INTERACTION). 687 688 -s <file> Write output to <file>. 689 690 -x Sets 'SKIP_SLOW_TESTS' environmental variable. 691 692 --verbose 693 -v Verbose mode. 694 695 --help 696 -h This Help. 697 698 --html <file> Generate HTML output. 699 700 --temp-source <sdir> --temp-target <tdir> [--temp-urlbase <url>] 701 Write temporary files to <tdir> by replacing <sdir> from the 702 filenames to generate with <tdir>. If --html is being used and 703 <url> given then the generated links are relative and prefixed 704 with the given url. In general you want to make <sdir> the path 705 to your source files and <tdir> some pach in your web page 706 hierarchy with <url> pointing to <tdir>. 707 708 --keep-[all|php|skip|clean] 709 Do not delete 'all' files, 'php' test file, 'skip' or 'clean' 710 file. 711 712 --set-timeout [n] 713 Set timeout for individual tests, where [n] is the number of 714 seconds. The default value is 60 seconds, or 300 seconds when 715 testing for memory leaks. 716 717 --show-[all|php|skip|clean|exp|diff|out] 718 Show 'all' files, 'php' test file, 'skip' or 'clean' file. You 719 can also use this to show the output 'out', the expected result 720 'exp' or the difference between them 'diff'. The result types 721 get written independent of the log format, however 'diff' only 722 exists when a test fails. 723 724 --no-clean Do not execute clean section if any. 725 726HELP; 727 exit(1); 728 } 729 } 730 731 if (!$is_switch) { 732 $testfile = realpath($argv[$i]); 733 734 if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) { 735 736 if (preg_match("/\.phpt$/", $argv[$i])) { 737 $pattern_match = glob($argv[$i]); 738 } else if (preg_match("/\*$/", $argv[$i])) { 739 $pattern_match = glob($argv[$i] . '.phpt'); 740 } else { 741 die("bogus test name " . $argv[$i] . "\n"); 742 } 743 744 if (is_array($pattern_match)) { 745 $test_files = array_merge($test_files, $pattern_match); 746 } 747 748 } else if (is_dir($testfile)) { 749 find_files($testfile); 750 } else if (preg_match("/\.phpt$/", $testfile)) { 751 $test_files[] = $testfile; 752 } else { 753 die("bogus test name " . $argv[$i] . "\n"); 754 } 755 } 756 } 757 758 if (strlen($conf_passed)) { 759 if (substr(PHP_OS, 0, 3) == "WIN") { 760 $pass_options .= " -c " . escapeshellarg($conf_passed); 761 } else { 762 $pass_options .= " -c '$conf_passed'"; 763 } 764 } 765 766 $test_files = array_unique($test_files); 767 $test_files = array_merge($test_files, $redir_tests); 768 769 // Run selected tests. 770 $test_cnt = count($test_files); 771 772 if ($test_cnt) { 773 putenv('NO_INTERACTION=1'); 774 verify_config(); 775 write_information($html_output); 776 usort($test_files, "test_sort"); 777 $start_time = time(); 778 779 if (!$html_output) { 780 echo "Running selected tests.\n"; 781 } else { 782 show_start($start_time); 783 } 784 785 $test_idx = 0; 786 run_all_tests($test_files, $environment); 787 $end_time = time(); 788 789 if ($html_output) { 790 show_end($end_time); 791 } 792 793 if ($failed_tests_file) { 794 fclose($failed_tests_file); 795 } 796 797 if (count($test_files) || count($test_results)) { 798 compute_summary(); 799 if ($html_output) { 800 fwrite($html_file, "<hr/>\n" . get_summary(false, true)); 801 } 802 echo "====================================================================="; 803 echo get_summary(false, false); 804 } 805 806 if ($html_output) { 807 fclose($html_file); 808 } 809 810 if ($output_file != '' && $just_save_results) { 811 save_or_mail_results(); 812 } 813 814 junit_save_xml(); 815 816 if (getenv('REPORT_EXIT_STATUS') == 1 and preg_match('/FAILED(?: |$)/', implode(' ', $test_results))) { 817 exit(1); 818 } 819 820 exit(0); 821 } 822} 823 824verify_config(); 825write_information($html_output); 826 827// Compile a list of all test files (*.phpt). 828$test_files = array(); 829$exts_tested = count($exts_to_test); 830$exts_skipped = 0; 831$ignored_by_ext = 0; 832sort($exts_to_test); 833$test_dirs = array(); 834$optionals = array('tests', 'ext', 'Zend', 'ZendEngine2', 'sapi/cli', 'sapi/cgi'); 835 836foreach($optionals as $dir) { 837 if (@filetype($dir) == 'dir') { 838 $test_dirs[] = $dir; 839 } 840} 841 842// Convert extension names to lowercase 843foreach ($exts_to_test as $key => $val) { 844 $exts_to_test[$key] = strtolower($val); 845} 846 847foreach ($test_dirs as $dir) { 848 find_files("{$cwd}/{$dir}", ($dir == 'ext')); 849} 850 851foreach ($user_tests as $dir) { 852 find_files($dir, ($dir == 'ext')); 853} 854 855function find_files($dir, $is_ext_dir = false, $ignore = false) 856{ 857 global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped, $exts_tested; 858 859 $o = opendir($dir) or error("cannot open directory: $dir"); 860 861 while (($name = readdir($o)) !== false) { 862 863 if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', '.svn'))) { 864 $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test)); 865 if ($skip_ext) { 866 $exts_skipped++; 867 } 868 find_files("{$dir}/{$name}", false, $ignore || $skip_ext); 869 } 870 871 // Cleanup any left-over tmp files from last run. 872 if (substr($name, -4) == '.tmp') { 873 @unlink("$dir/$name"); 874 continue; 875 } 876 877 // Otherwise we're only interested in *.phpt files. 878 if (substr($name, -5) == '.phpt') { 879 if ($ignore) { 880 $ignored_by_ext++; 881 } else { 882 $testfile = realpath("{$dir}/{$name}"); 883 $test_files[] = $testfile; 884 } 885 } 886 } 887 888 closedir($o); 889} 890 891function test_name($name) 892{ 893 if (is_array($name)) { 894 return $name[0] . ':' . $name[1]; 895 } else { 896 return $name; 897 } 898} 899 900function test_sort($a, $b) 901{ 902 global $cwd; 903 904 $a = test_name($a); 905 $b = test_name($b); 906 907 $ta = strpos($a, "{$cwd}/tests") === 0 ? 1 + (strpos($a, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0; 908 $tb = strpos($b, "{$cwd}/tests") === 0 ? 1 + (strpos($b, "{$cwd}/tests/run-test") === 0 ? 1 : 0) : 0; 909 910 if ($ta == $tb) { 911 return strcmp($a, $b); 912 } else { 913 return $tb - $ta; 914 } 915} 916 917$test_files = array_unique($test_files); 918usort($test_files, "test_sort"); 919 920$start_time = time(); 921show_start($start_time); 922 923$test_cnt = count($test_files); 924$test_idx = 0; 925run_all_tests($test_files, $environment); 926$end_time = time(); 927 928if ($failed_tests_file) { 929 fclose($failed_tests_file); 930} 931 932// Summarize results 933 934if (0 == count($test_results)) { 935 echo "No tests were run.\n"; 936 return; 937} 938 939compute_summary(); 940 941show_end($end_time); 942show_summary(); 943 944if ($html_output) { 945 fclose($html_file); 946} 947 948save_or_mail_results(); 949 950junit_save_xml(); 951 952if (getenv('REPORT_EXIT_STATUS') == 1 and $sum_results['FAILED']) { 953 exit(1); 954} 955exit(0); 956 957// 958// Send Email to QA Team 959// 960 961function mail_qa_team($data, $compression, $status = false) 962{ 963 $url_bits = parse_url(QA_SUBMISSION_PAGE); 964 965 if (($proxy = getenv('http_proxy'))) { 966 $proxy = parse_url($proxy); 967 $path = $url_bits['host'].$url_bits['path']; 968 $host = $proxy['host']; 969 if (empty($proxy['port'])) { 970 $proxy['port'] = 80; 971 } 972 $port = $proxy['port']; 973 } else { 974 $path = $url_bits['path']; 975 $host = $url_bits['host']; 976 $port = empty($url_bits['port']) ? 80 : $port = $url_bits['port']; 977 } 978 979 $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data))); 980 $data_length = strlen($data); 981 982 $fs = fsockopen($host, $port, $errno, $errstr, 10); 983 984 if (!$fs) { 985 return false; 986 } 987 988 $php_version = urlencode(TESTED_PHP_VERSION); 989 990 echo "\nPosting to ". QA_SUBMISSION_PAGE . "\n"; 991 fwrite($fs, "POST " . $path . "?status=$status&version=$php_version HTTP/1.1\r\n"); 992 fwrite($fs, "Host: " . $host . "\r\n"); 993 fwrite($fs, "User-Agent: QA Browser 0.1\r\n"); 994 fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n"); 995 fwrite($fs, "Content-Length: " . $data_length . "\r\n\r\n"); 996 fwrite($fs, $data); 997 fwrite($fs, "\r\n\r\n"); 998 fclose($fs); 999 1000 return 1; 1001} 1002 1003 1004// 1005// Write the given text to a temporary file, and return the filename. 1006// 1007 1008function save_text($filename, $text, $filename_copy = null) 1009{ 1010 global $DETAILED; 1011 1012 if ($filename_copy && $filename_copy != $filename) { 1013 if (file_put_contents($filename_copy, $text, FILE_BINARY) === false) { 1014 error("Cannot open file '" . $filename_copy . "' (save_text)"); 1015 } 1016 } 1017 1018 if (file_put_contents($filename, $text, FILE_BINARY) === false) { 1019 error("Cannot open file '" . $filename . "' (save_text)"); 1020 } 1021 1022 if (1 < $DETAILED) echo " 1023FILE $filename {{{ 1024$text 1025}}} 1026"; 1027} 1028 1029// 1030// Write an error in a format recognizable to Emacs or MSVC. 1031// 1032 1033function error_report($testname, $logname, $tested) 1034{ 1035 $testname = realpath($testname); 1036 $logname = realpath($logname); 1037 1038 switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) { 1039 case 'MSVC': 1040 echo $testname . "(1) : $tested\n"; 1041 echo $logname . "(1) : $tested\n"; 1042 break; 1043 case 'EMACS': 1044 echo $testname . ":1: $tested\n"; 1045 echo $logname . ":1: $tested\n"; 1046 break; 1047 } 1048} 1049 1050function system_with_timeout($commandline, $env = null, $stdin = null) 1051{ 1052 global $leak_check, $cwd; 1053 1054 $data = ''; 1055 1056 $bin_env = array(); 1057 foreach((array)$env as $key => $value) { 1058 $bin_env[$key] = $value; 1059 } 1060 1061 $proc = proc_open($commandline, array( 1062 0 => array('pipe', 'r'), 1063 1 => array('pipe', 'w'), 1064 2 => array('pipe', 'w') 1065 ), $pipes, $cwd, $bin_env, array('suppress_errors' => true, 'binary_pipes' => true)); 1066 1067 if (!$proc) { 1068 return false; 1069 } 1070 1071 if (!is_null($stdin)) { 1072 fwrite($pipes[0], $stdin); 1073 } 1074 fclose($pipes[0]); 1075 1076 $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60); 1077 1078 while (true) { 1079 /* hide errors from interrupted syscalls */ 1080 $r = $pipes; 1081 $w = null; 1082 $e = null; 1083 1084 $n = @stream_select($r, $w, $e, $timeout); 1085 1086 if ($n === false) { 1087 break; 1088 } else if ($n === 0) { 1089 /* timed out */ 1090 $data .= "\n ** ERROR: process timed out **\n"; 1091 proc_terminate($proc, 9); 1092 return $data; 1093 } else if ($n > 0) { 1094 $line = fread($pipes[1], 8192); 1095 if (strlen($line) == 0) { 1096 /* EOF */ 1097 break; 1098 } 1099 $data .= $line; 1100 } 1101 } 1102 1103 $stat = proc_get_status($proc); 1104 1105 if ($stat['signaled']) { 1106 $data .= "\nTermsig=" . $stat['stopsig']; 1107 } 1108 1109 $code = proc_close($proc); 1110 return $data; 1111} 1112 1113function run_all_tests($test_files, $env, $redir_tested = null) 1114{ 1115 global $test_results, $failed_tests_file, $php, $test_cnt, $test_idx; 1116 1117 foreach($test_files as $name) { 1118 1119 if (is_array($name)) { 1120 $index = "# $name[1]: $name[0]"; 1121 1122 if ($redir_tested) { 1123 $name = $name[0]; 1124 } 1125 } else if ($redir_tested) { 1126 $index = "# $redir_tested: $name"; 1127 } else { 1128 $index = $name; 1129 } 1130 $test_idx++; 1131 $result = run_test($php, $name, $env); 1132 1133 if (!is_array($name) && $result != 'REDIR') { 1134 $test_results[$index] = $result; 1135 if ($failed_tests_file && ($result == 'XFAILED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) { 1136 fwrite($failed_tests_file, "$index\n"); 1137 } 1138 } 1139 } 1140} 1141 1142// 1143// Show file or result block 1144// 1145function show_file_block($file, $block, $section = null) 1146{ 1147 global $cfg; 1148 1149 if ($cfg['show'][$file]) { 1150 1151 if (is_null($section)) { 1152 $section = strtoupper($file); 1153 } 1154 1155 echo "\n========" . $section . "========\n"; 1156 echo rtrim($block); 1157 echo "\n========DONE========\n"; 1158 } 1159} 1160 1161// 1162// Run an individual test case. 1163// 1164function run_test($php, $file, $env) 1165{ 1166 global $log_format, $info_params, $ini_overwrites, $cwd, $PHP_FAILED_TESTS; 1167 global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx; 1168 global $leak_check, $temp_source, $temp_target, $cfg, $environment; 1169 global $no_clean; 1170 global $valgrind_version; 1171 global $JUNIT; 1172 $temp_filenames = null; 1173 $org_file = $file; 1174 1175 if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) { 1176 $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE']; 1177 } 1178 1179 if (is_array($file)) { 1180 $file = $file[0]; 1181 } 1182 1183 if ($DETAILED) echo " 1184================= 1185TEST $file 1186"; 1187 1188 // Load the sections of the test file. 1189 $section_text = array('TEST' => ''); 1190 1191 $fp = fopen($file, "rb") or error("Cannot open test file: $file"); 1192 1193 $borked = false; 1194 $bork_info = ''; 1195 1196 if (!feof($fp)) { 1197 $line = fgets($fp); 1198 1199 if ($line === false) { 1200 $bork_info = "cannot read test"; 1201 $borked = true; 1202 } 1203 } else { 1204 $bork_info = "empty test [$file]"; 1205 $borked = true; 1206 } 1207 if (!$borked && strncmp('--TEST--', $line, 8)) { 1208 $bork_info = "tests must start with --TEST-- [$file]"; 1209 $borked = true; 1210 } 1211 1212 $section = 'TEST'; 1213 $secfile = false; 1214 $secdone = false; 1215 1216 while (!feof($fp)) { 1217 $line = fgets($fp); 1218 1219 if ($line === false) { 1220 break; 1221 } 1222 1223 // Match the beginning of a section. 1224 if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { 1225 $section = $r[1]; 1226 settype($section, 'string'); 1227 1228 if (isset($section_text[$section])) { 1229 $bork_info = "duplicated $section section"; 1230 $borked = true; 1231 } 1232 1233 $section_text[$section] = ''; 1234 $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL'; 1235 $secdone = false; 1236 continue; 1237 } 1238 1239 // Add to the section text. 1240 if (!$secdone) { 1241 $section_text[$section] .= $line; 1242 } 1243 1244 // End of actual test? 1245 if ($secfile && preg_match('/^===DONE===\s*$/', $line)) { 1246 $secdone = true; 1247 } 1248 } 1249 1250 // the redirect section allows a set of tests to be reused outside of 1251 // a given test dir 1252 if (!$borked) { 1253 if (@count($section_text['REDIRECTTEST']) == 1) { 1254 1255 if ($IN_REDIRECT) { 1256 $borked = true; 1257 $bork_info = "Can't redirect a test from within a redirected test"; 1258 } else { 1259 $borked = false; 1260 } 1261 1262 } else { 1263 1264 if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) { 1265 $bork_info = "missing section --FILE--"; 1266 $borked = true; 1267 } 1268 1269 if (@count($section_text['FILEEOF']) == 1) { 1270 $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']); 1271 unset($section_text['FILEEOF']); 1272 } 1273 1274 if (@count($section_text['FILE_EXTERNAL']) == 1) { 1275 // don't allow tests to retrieve files from anywhere but this subdirectory 1276 $section_text['FILE_EXTERNAL'] = dirname($file) . '/' . trim(str_replace('..', '', $section_text['FILE_EXTERNAL'])); 1277 1278 if (file_exists($section_text['FILE_EXTERNAL'])) { 1279 $section_text['FILE'] = file_get_contents($section_text['FILE_EXTERNAL'], FILE_BINARY); 1280 unset($section_text['FILE_EXTERNAL']); 1281 } else { 1282 $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']); 1283 $borked = true; 1284 } 1285 } 1286 1287 if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) { 1288 $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--"; 1289 $borked = true; 1290 } 1291 } 1292 } 1293 fclose($fp); 1294 1295 $shortname = str_replace($cwd . '/', '', $file); 1296 $tested_file = $shortname; 1297 1298 if ($borked) { 1299 show_result("BORK", $bork_info, $tested_file); 1300 $PHP_FAILED_TESTS['BORKED'][] = array ( 1301 'name' => $file, 1302 'test_name' => '', 1303 'output' => '', 1304 'diff' => '', 1305 'info' => "$bork_info [$file]", 1306 ); 1307 1308 junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info); 1309 return 'BORKED'; 1310 } 1311 1312 $tested = trim($section_text['TEST']); 1313 1314 /* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */ 1315 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'])) { 1316 if (isset($php_cgi)) { 1317 $old_php = $php; 1318 $php = $php_cgi . ' -C '; 1319 } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) { 1320 $old_php = $php; 1321 $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C '; 1322 } else { 1323 if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) { 1324 $old_php = $php; 1325 $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C '; 1326 } else if (file_exists("./sapi/cgi/php-cgi")) { 1327 $old_php = $php; 1328 $php = realpath("./sapi/cgi/php-cgi") . ' -C '; 1329 } else if (file_exists(dirname($php) . "/php-cgi")) { 1330 $old_php = $php; 1331 $php = realpath(dirname($php) . "/php-cgi") . ' -C '; 1332 } else { 1333 show_result('SKIP', $tested, $tested_file, "reason: CGI not available"); 1334 1335 junit_mark_test_as('SKIP', $shortname, $tested, 0, 'CGI not available'); 1336 return 'SKIPPED'; 1337 } 1338 } 1339 } 1340 1341 show_test($test_idx, $shortname); 1342 1343 if (is_array($IN_REDIRECT)) { 1344 $temp_dir = $test_dir = $IN_REDIRECT['dir']; 1345 } else { 1346 $temp_dir = $test_dir = realpath(dirname($file)); 1347 } 1348 1349 if ($temp_source && $temp_target) { 1350 $temp_dir = str_replace($temp_source, $temp_target, $temp_dir); 1351 } 1352 1353 $main_file_name = basename($file,'phpt'); 1354 1355 $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff'; 1356 $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log'; 1357 $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp'; 1358 $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out'; 1359 $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem'; 1360 $sh_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'sh'; 1361 $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; 1362 $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; 1363 $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; 1364 $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; 1365 $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; 1366 $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; 1367 $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.'); 1368 $tmp_relative_file = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $test_file) . 't'; 1369 1370 if ($temp_source && $temp_target) { 1371 $temp_skipif .= 's'; 1372 $temp_file .= 's'; 1373 $temp_clean .= 's'; 1374 $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps'; 1375 1376 if (!is_dir(dirname($copy_file))) { 1377 mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file)); 1378 } 1379 1380 if (isset($section_text['FILE'])) { 1381 save_text($copy_file, $section_text['FILE']); 1382 } 1383 1384 $temp_filenames = array( 1385 'file' => $copy_file, 1386 'diff' => $diff_filename, 1387 'log' => $log_filename, 1388 'exp' => $exp_filename, 1389 'out' => $output_filename, 1390 'mem' => $memcheck_filename, 1391 'sh' => $sh_filename, 1392 'php' => $temp_file, 1393 'skip' => $temp_skipif, 1394 'clean'=> $temp_clean); 1395 } 1396 1397 if (is_array($IN_REDIRECT)) { 1398 $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']); 1399 $tested_file = $tmp_relative_file; 1400 } 1401 1402 // unlink old test results 1403 @unlink($diff_filename); 1404 @unlink($log_filename); 1405 @unlink($exp_filename); 1406 @unlink($output_filename); 1407 @unlink($memcheck_filename); 1408 @unlink($sh_filename); 1409 @unlink($temp_file); 1410 @unlink($test_file); 1411 @unlink($temp_skipif); 1412 @unlink($test_skipif); 1413 @unlink($tmp_post); 1414 @unlink($temp_clean); 1415 @unlink($test_clean); 1416 1417 // Reset environment from any previous test. 1418 $env['REDIRECT_STATUS'] = ''; 1419 $env['QUERY_STRING'] = ''; 1420 $env['PATH_TRANSLATED'] = ''; 1421 $env['SCRIPT_FILENAME'] = ''; 1422 $env['REQUEST_METHOD'] = ''; 1423 $env['CONTENT_TYPE'] = ''; 1424 $env['CONTENT_LENGTH'] = ''; 1425 $env['TZ'] = ''; 1426 1427 if (!empty($section_text['ENV'])) { 1428 1429 foreach(explode("\n", trim($section_text['ENV'])) as $e) { 1430 $e = explode('=', trim($e), 2); 1431 1432 if (!empty($e[0]) && isset($e[1])) { 1433 $env[$e[0]] = $e[1]; 1434 } 1435 } 1436 } 1437 1438 // Default ini settings 1439 $ini_settings = array(); 1440 // additional ini overwrites 1441 //$ini_overwrites[] = 'setting=value'; 1442 settings2array($ini_overwrites, $ini_settings); 1443 1444 // Any special ini settings 1445 // these may overwrite the test defaults... 1446 if (array_key_exists('INI', $section_text)) { 1447 if (strpos($section_text['INI'], '{PWD}') !== false) { 1448 $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); 1449 } 1450 settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings); 1451 } 1452 1453 // Additional required extensions 1454 if (array_key_exists('EXTENSIONS', $section_text)) { 1455 $ext_dir=`$php -r 'echo ini_get("extension_dir");'`; 1456 $extensions = preg_split("/[\n\r]+/", trim($section_text['EXTENSIONS'])); 1457 $loaded = explode(",", `$php -n -r 'echo join(",", get_loaded_extensions());'`); 1458 foreach ($extensions as $req_ext) { 1459 if (!in_array($req_ext, $loaded)) { 1460 $ini_settings['extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $req_ext . '.' . PHP_SHLIB_SUFFIX; 1461 } 1462 } 1463 } 1464 1465 settings2params($ini_settings); 1466 1467 // Check if test should be skipped. 1468 $info = ''; 1469 $warn = false; 1470 1471 if (array_key_exists('SKIPIF', $section_text)) { 1472 1473 if (trim($section_text['SKIPIF'])) { 1474 show_file_block('skip', $section_text['SKIPIF']); 1475 save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif); 1476 $extra = substr(PHP_OS, 0, 3) !== "WIN" ? 1477 "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": ""; 1478 1479 if ($leak_check) { 1480 $env['USE_ZEND_ALLOC'] = '0'; 1481 $env['ZEND_DONT_UNLOAD_MODULES'] = 1; 1482 } else { 1483 $env['USE_ZEND_ALLOC'] = '1'; 1484 $env['ZEND_DONT_UNLOAD_MODULES'] = 0; 1485 } 1486 1487 junit_start_timer($shortname); 1488 1489 $output = system_with_timeout("$extra $php $pass_options -q $ini_settings -d display_errors=0 \"$test_skipif\"", $env); 1490 1491 junit_finish_timer($shortname); 1492 1493 if (!$cfg['keep']['skip']) { 1494 @unlink($test_skipif); 1495 } 1496 1497 if (!strncasecmp('skip', ltrim($output), 4)) { 1498 1499 if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { 1500 show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames); 1501 } else { 1502 show_result('SKIP', $tested, $tested_file, '', $temp_filenames); 1503 } 1504 1505 if (isset($old_php)) { 1506 $php = $old_php; 1507 } 1508 1509 if (!$cfg['keep']['skip']) { 1510 @unlink($test_skipif); 1511 } 1512 1513 $message = !empty($m[1]) ? $m[1] : ''; 1514 junit_mark_test_as('SKIP', $shortname, $tested, null, "<![CDATA[\n$message\n]]>"); 1515 return 'SKIPPED'; 1516 } 1517 1518 if (!strncasecmp('info', ltrim($output), 4)) { 1519 if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { 1520 $info = " (info: $m[1])"; 1521 } 1522 } 1523 1524 if (!strncasecmp('warn', ltrim($output), 4)) { 1525 if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { 1526 $warn = true; /* only if there is a reason */ 1527 $info = " (warn: $m[1])"; 1528 } 1529 } 1530 } 1531 } 1532 1533 if (@count($section_text['REDIRECTTEST']) == 1) { 1534 $test_files = array(); 1535 1536 $IN_REDIRECT = eval($section_text['REDIRECTTEST']); 1537 $IN_REDIRECT['via'] = "via [$shortname]\n\t"; 1538 $IN_REDIRECT['dir'] = realpath(dirname($file)); 1539 $IN_REDIRECT['prefix'] = trim($section_text['TEST']); 1540 1541 if (count($IN_REDIRECT['TESTS']) == 1) { 1542 1543 if (is_array($org_file)) { 1544 $test_files[] = $org_file[1]; 1545 } else { 1546 $GLOBALS['test_files'] = $test_files; 1547 find_files($IN_REDIRECT['TESTS']); 1548 1549 foreach($GLOBALS['test_files'] as $f) { 1550 $test_files[] = array($f, $file); 1551 } 1552 } 1553 $test_cnt += @count($test_files) - 1; 1554 $test_idx--; 1555 1556 show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file); 1557 1558 // set up environment 1559 $redirenv = array_merge($environment, $IN_REDIRECT['ENV']); 1560 $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR; 1561 1562 usort($test_files, "test_sort"); 1563 run_all_tests($test_files, $redirenv, $tested); 1564 1565 show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file); 1566 1567 // a redirected test never fails 1568 $IN_REDIRECT = false; 1569 1570 junit_mark_test_as('PASS', $shortname, $tested); 1571 return 'REDIR'; 1572 1573 } else { 1574 1575 $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory."; 1576 show_result("BORK", $bork_info, '', $temp_filenames); 1577 $PHP_FAILED_TESTS['BORKED'][] = array ( 1578 'name' => $file, 1579 'test_name' => '', 1580 'output' => '', 1581 'diff' => '', 1582 'info' => "$bork_info [$file]", 1583 ); 1584 } 1585 } 1586 1587 if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) { 1588 1589 if (is_array($org_file)) { 1590 $file = $org_file[0]; 1591 } 1592 1593 $bork_info = "Redirected test did not contain redirection info"; 1594 show_result("BORK", $bork_info, '', $temp_filenames); 1595 $PHP_FAILED_TESTS['BORKED'][] = array ( 1596 'name' => $file, 1597 'test_name' => '', 1598 'output' => '', 1599 'diff' => '', 1600 'info' => "$bork_info [$file]", 1601 ); 1602 1603 junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info); 1604 1605 return 'BORKED'; 1606 } 1607 1608 // We've satisfied the preconditions - run the test! 1609 show_file_block('php', $section_text['FILE'], 'TEST'); 1610 save_text($test_file, $section_text['FILE'], $temp_file); 1611 1612 if (array_key_exists('GET', $section_text)) { 1613 $query_string = trim($section_text['GET']); 1614 } else { 1615 $query_string = ''; 1616 } 1617 1618 $env['REDIRECT_STATUS'] = '1'; 1619 $env['QUERY_STRING'] = $query_string; 1620 $env['PATH_TRANSLATED'] = $test_file; 1621 $env['SCRIPT_FILENAME'] = $test_file; 1622 1623 if (array_key_exists('COOKIE', $section_text)) { 1624 $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); 1625 } else { 1626 $env['HTTP_COOKIE'] = ''; 1627 } 1628 1629 $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : ''; 1630 1631 if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { 1632 1633 $post = trim($section_text['POST_RAW']); 1634 $raw_lines = explode("\n", $post); 1635 1636 $request = ''; 1637 $started = false; 1638 1639 foreach ($raw_lines as $line) { 1640 1641 if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { 1642 $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); 1643 continue; 1644 } 1645 1646 if ($started) { 1647 $request .= "\n"; 1648 } 1649 1650 $started = true; 1651 $request .= $line; 1652 } 1653 1654 $env['CONTENT_LENGTH'] = strlen($request); 1655 $env['REQUEST_METHOD'] = 'POST'; 1656 1657 if (empty($request)) { 1658 junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request'); 1659 return 'BORKED'; 1660 } 1661 1662 save_text($tmp_post, $request); 1663 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; 1664 1665 } elseif (array_key_exists('PUT', $section_text) && !empty($section_text['PUT'])) { 1666 1667 $post = trim($section_text['PUT']); 1668 $raw_lines = explode("\n", $post); 1669 1670 $request = ''; 1671 $started = false; 1672 1673 foreach ($raw_lines as $line) { 1674 1675 if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { 1676 $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); 1677 continue; 1678 } 1679 1680 if ($started) { 1681 $request .= "\n"; 1682 } 1683 1684 $started = true; 1685 $request .= $line; 1686 } 1687 1688 $env['CONTENT_LENGTH'] = strlen($request); 1689 $env['REQUEST_METHOD'] = 'PUT'; 1690 1691 if (empty($request)) { 1692 junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request'); 1693 return 'BORKED'; 1694 } 1695 1696 save_text($tmp_post, $request); 1697 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; 1698 1699 } else if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { 1700 1701 $post = trim($section_text['POST']); 1702 save_text($tmp_post, $post); 1703 $content_length = strlen($post); 1704 1705 $env['REQUEST_METHOD'] = 'POST'; 1706 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; 1707 $env['CONTENT_LENGTH'] = $content_length; 1708 1709 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; 1710 1711 } else if (array_key_exists('GZIP_POST', $section_text) && !empty($section_text['GZIP_POST'])) { 1712 1713 $post = trim($section_text['GZIP_POST']); 1714 $post = gzencode($post, 9, FORCE_GZIP); 1715 $env['HTTP_CONTENT_ENCODING'] = 'gzip'; 1716 1717 save_text($tmp_post, $post); 1718 $content_length = strlen($post); 1719 1720 $env['REQUEST_METHOD'] = 'POST'; 1721 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; 1722 $env['CONTENT_LENGTH'] = $content_length; 1723 1724 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; 1725 1726 } else if (array_key_exists('DEFLATE_POST', $section_text) && !empty($section_text['DEFLATE_POST'])) { 1727 $post = trim($section_text['DEFLATE_POST']); 1728 $post = gzcompress($post, 9); 1729 $env['HTTP_CONTENT_ENCODING'] = 'deflate'; 1730 save_text($tmp_post, $post); 1731 $content_length = strlen($post); 1732 1733 $env['REQUEST_METHOD'] = 'POST'; 1734 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; 1735 $env['CONTENT_LENGTH'] = $content_length; 1736 1737 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < \"$tmp_post\""; 1738 1739 1740 } else { 1741 1742 $env['REQUEST_METHOD'] = 'GET'; 1743 $env['CONTENT_TYPE'] = ''; 1744 $env['CONTENT_LENGTH'] = ''; 1745 1746 $cmd = "$php $pass_options $ini_settings -f \"$test_file\" $args 2>&1"; 1747 } 1748 1749 if ($leak_check) { 1750 $env['USE_ZEND_ALLOC'] = '0'; 1751 $env['ZEND_DONT_UNLOAD_MODULES'] = 1; 1752 1753 if ($valgrind_version >= 330) { 1754 /* valgrind 3.3.0+ doesn't have --log-file-exactly option */ 1755 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file=$memcheck_filename $cmd"; 1756 } else { 1757 $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd"; 1758 } 1759 1760 } else { 1761 $env['USE_ZEND_ALLOC'] = '1'; 1762 $env['ZEND_DONT_UNLOAD_MODULES'] = 0; 1763 } 1764 1765 if ($DETAILED) echo " 1766CONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . " 1767CONTENT_TYPE = " . $env['CONTENT_TYPE'] . " 1768PATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . " 1769QUERY_STRING = " . $env['QUERY_STRING'] . " 1770REDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . " 1771REQUEST_METHOD = " . $env['REQUEST_METHOD'] . " 1772SCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . " 1773HTTP_COOKIE = " . $env['HTTP_COOKIE'] . " 1774COMMAND $cmd 1775"; 1776 1777 junit_start_timer($shortname); 1778 1779 $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null); 1780 1781 junit_finish_timer($shortname); 1782 1783 if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) { 1784 1785 if (trim($section_text['CLEAN'])) { 1786 show_file_block('clean', $section_text['CLEAN']); 1787 save_text($test_clean, trim($section_text['CLEAN']), $temp_clean); 1788 1789 if (!$no_clean) { 1790 $clean_params = array(); 1791 settings2array($ini_overwrites, $clean_params); 1792 settings2params($clean_params); 1793 $extra = substr(PHP_OS, 0, 3) !== "WIN" ? 1794 "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": ""; 1795 system_with_timeout("$extra $php $pass_options -q $clean_params \"$test_clean\"", $env); 1796 } 1797 1798 if (!$cfg['keep']['clean']) { 1799 @unlink($test_clean); 1800 } 1801 } 1802 } 1803 1804 @unlink($tmp_post); 1805 1806 $leaked = false; 1807 $passed = false; 1808 1809 if ($leak_check) { // leak check 1810 $leaked = filesize($memcheck_filename) > 0; 1811 1812 if (!$leaked) { 1813 @unlink($memcheck_filename); 1814 } 1815 } 1816 1817 // Does the output match what is expected? 1818 $output = preg_replace("/\r\n/", "\n", trim($out)); 1819 1820 /* when using CGI, strip the headers from the output */ 1821 $headers = ""; 1822 1823 if (isset($old_php) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) { 1824 $output = trim($match[2]); 1825 $rh = preg_split("/[\n\r]+/", $match[1]); 1826 $headers = array(); 1827 1828 foreach ($rh as $line) { 1829 if (strpos($line, ':') !== false) { 1830 $line = explode(':', $line, 2); 1831 $headers[trim($line[0])] = trim($line[1]); 1832 } 1833 } 1834 } 1835 1836 $failed_headers = false; 1837 1838 if (isset($section_text['EXPECTHEADERS'])) { 1839 $want = array(); 1840 $wanted_headers = array(); 1841 $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']); 1842 1843 foreach($lines as $line) { 1844 if (strpos($line, ':') !== false) { 1845 $line = explode(':', $line, 2); 1846 $want[trim($line[0])] = trim($line[1]); 1847 $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]); 1848 } 1849 } 1850 1851 $org_headers = $headers; 1852 $headers = array(); 1853 $output_headers = array(); 1854 1855 foreach($want as $k => $v) { 1856 1857 if (isset($org_headers[$k])) { 1858 $headers = $org_headers[$k]; 1859 $output_headers[] = $k . ': ' . $org_headers[$k]; 1860 } 1861 1862 if (!isset($org_headers[$k]) || $org_headers[$k] != $v) { 1863 $failed_headers = true; 1864 } 1865 } 1866 1867 ksort($wanted_headers); 1868 $wanted_headers = join("\n", $wanted_headers); 1869 ksort($output_headers); 1870 $output_headers = join("\n", $output_headers); 1871 } 1872 1873 show_file_block('out', $output); 1874 1875 if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { 1876 1877 if (isset($section_text['EXPECTF'])) { 1878 $wanted = trim($section_text['EXPECTF']); 1879 } else { 1880 $wanted = trim($section_text['EXPECTREGEX']); 1881 } 1882 1883 show_file_block('exp', $wanted); 1884 $wanted_re = preg_replace('/\r\n/', "\n", $wanted); 1885 1886 if (isset($section_text['EXPECTF'])) { 1887 1888 // do preg_quote, but miss out any %r delimited sections 1889 $temp = ""; 1890 $r = "%r"; 1891 $startOffset = 0; 1892 $length = strlen($wanted_re); 1893 while($startOffset < $length) { 1894 $start = strpos($wanted_re, $r, $startOffset); 1895 if ($start !== false) { 1896 // we have found a start tag 1897 $end = strpos($wanted_re, $r, $start+2); 1898 if ($end === false) { 1899 // unbalanced tag, ignore it. 1900 $end = $start = $length; 1901 } 1902 } else { 1903 // no more %r sections 1904 $start = $end = $length; 1905 } 1906 // quote a non re portion of the string 1907 $temp = $temp . preg_quote(substr($wanted_re, $startOffset, ($start - $startOffset)), '/'); 1908 // add the re unquoted. 1909 if ($end > $start) { 1910 $temp = $temp . '(' . substr($wanted_re, $start+2, ($end - $start-2)). ')'; 1911 } 1912 $startOffset = $end + 2; 1913 } 1914 $wanted_re = $temp; 1915 1916 $wanted_re = str_replace( 1917 array('%binary_string_optional%'), 1918 'string', 1919 $wanted_re 1920 ); 1921 $wanted_re = str_replace( 1922 array('%unicode_string_optional%'), 1923 'string', 1924 $wanted_re 1925 ); 1926 $wanted_re = str_replace( 1927 array('%unicode\|string%', '%string\|unicode%'), 1928 'string', 1929 $wanted_re 1930 ); 1931 $wanted_re = str_replace( 1932 array('%u\|b%', '%b\|u%'), 1933 '', 1934 $wanted_re 1935 ); 1936 // Stick to basics 1937 $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re); 1938 $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re); 1939 $wanted_re = str_replace('%S', '[^\r\n]*', $wanted_re); 1940 $wanted_re = str_replace('%a', '.+', $wanted_re); 1941 $wanted_re = str_replace('%A', '.*', $wanted_re); 1942 $wanted_re = str_replace('%w', '\s*', $wanted_re); 1943 $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re); 1944 $wanted_re = str_replace('%d', '\d+', $wanted_re); 1945 $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re); 1946 $wanted_re = str_replace('%f', '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', $wanted_re); 1947 $wanted_re = str_replace('%c', '.', $wanted_re); 1948 // %f allows two points "-.0.0" but that is the best *simple* expression 1949 } 1950/* DEBUG YOUR REGEX HERE 1951 var_dump($wanted_re); 1952 print(str_repeat('=', 80) . "\n"); 1953 var_dump($output); 1954*/ 1955 if (preg_match("/^$wanted_re\$/s", $output)) { 1956 $passed = true; 1957 if (!$cfg['keep']['php']) { 1958 @unlink($test_file); 1959 } 1960 if (isset($old_php)) { 1961 $php = $old_php; 1962 } 1963 1964 if (!$leaked && !$failed_headers) { 1965 if (isset($section_text['XFAIL'] )) { 1966 $warn = true; 1967 $info = " (warn: XFAIL section but test passes)"; 1968 }else { 1969 show_result("PASS", $tested, $tested_file, '', $temp_filenames); 1970 junit_mark_test_as('PASS', $shortname, $tested); 1971 return 'PASSED'; 1972 } 1973 } 1974 } 1975 1976 } else { 1977 1978 $wanted = trim($section_text['EXPECT']); 1979 $wanted = preg_replace('/\r\n/',"\n", $wanted); 1980 show_file_block('exp', $wanted); 1981 1982 // compare and leave on success 1983 if (!strcmp($output, $wanted)) { 1984 $passed = true; 1985 1986 if (!$cfg['keep']['php']) { 1987 @unlink($test_file); 1988 } 1989 1990 if (isset($old_php)) { 1991 $php = $old_php; 1992 } 1993 1994 if (!$leaked && !$failed_headers) { 1995 if (isset($section_text['XFAIL'] )) { 1996 $warn = true; 1997 $info = " (warn: XFAIL section but test passes)"; 1998 }else { 1999 show_result("PASS", $tested, $tested_file, '', $temp_filenames); 2000 junit_mark_test_as('PASS', $shortname, $tested); 2001 return 'PASSED'; 2002 } 2003 } 2004 } 2005 2006 $wanted_re = null; 2007 } 2008 2009 // Test failed so we need to report details. 2010 if ($failed_headers) { 2011 $passed = false; 2012 $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted; 2013 $output = $output_headers . "\n--HEADERS--\n" . $output; 2014 2015 if (isset($wanted_re)) { 2016 $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re; 2017 } 2018 } 2019 2020 if ($leaked) { 2021 $restype[] = 'LEAK'; 2022 } 2023 2024 if ($warn) { 2025 $restype[] = 'WARN'; 2026 } 2027 2028 if (!$passed) { 2029 if (isset($section_text['XFAIL'])) { 2030 $restype[] = 'XFAIL'; 2031 $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']); 2032 } else { 2033 $restype[] = 'FAIL'; 2034 } 2035 } 2036 2037 if (!$passed) { 2038 2039 // write .exp 2040 if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, $wanted, FILE_BINARY) === false) { 2041 error("Cannot create expected test output - $exp_filename"); 2042 } 2043 2044 // write .out 2045 if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) { 2046 error("Cannot create test output - $output_filename"); 2047 } 2048 2049 // write .diff 2050 $diff = generate_diff($wanted, $wanted_re, $output); 2051 if (is_array($IN_REDIRECT)) { 2052 $diff = "# original source file: $shortname\n" . $diff; 2053 } 2054 show_file_block('diff', $diff); 2055 if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, $diff, FILE_BINARY) === false) { 2056 error("Cannot create test diff - $diff_filename"); 2057 } 2058 2059 // write .sh 2060 if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh 2061 2062{$cmd} 2063", FILE_BINARY) === false) { 2064 error("Cannot create test shell script - $sh_filename"); 2065 } 2066 chmod($sh_filename, 0755); 2067 2068 // write .log 2069 if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, " 2070---- EXPECTED OUTPUT 2071$wanted 2072---- ACTUAL OUTPUT 2073$output 2074---- FAILED 2075", FILE_BINARY) === false) { 2076 error("Cannot create test log - $log_filename"); 2077 error_report($file, $log_filename, $tested); 2078 } 2079 } 2080 2081 show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames); 2082 2083 foreach ($restype as $type) { 2084 $PHP_FAILED_TESTS[$type.'ED'][] = array ( 2085 'name' => $file, 2086 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", 2087 'output' => $output_filename, 2088 'diff' => $diff_filename, 2089 'info' => $info, 2090 ); 2091 } 2092 2093 if (isset($old_php)) { 2094 $php = $old_php; 2095 } 2096 2097 $diff = empty($diff) ? '' : "<![CDATA[\n " . preg_replace('/\e/', '<esc>', $diff) . "\n]]>"; 2098 2099 junit_mark_test_as($restype, str_replace($cwd . '/', '', $tested_file), $tested, null, $info, $diff); 2100 2101 return $restype[0] . 'ED'; 2102} 2103 2104function comp_line($l1, $l2, $is_reg) 2105{ 2106 if ($is_reg) { 2107 return preg_match('/^'. $l1 . '$/s', $l2); 2108 } else { 2109 return !strcmp($l1, $l2); 2110 } 2111} 2112 2113function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps) 2114{ 2115 $equal = 0; 2116 2117 while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { 2118 $idx1++; 2119 $idx2++; 2120 $equal++; 2121 $steps--; 2122 } 2123 if (--$steps > 0) { 2124 $eq1 = 0; 2125 $st = $steps / 2; 2126 2127 for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) { 2128 $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st); 2129 2130 if ($eq > $eq1) { 2131 $eq1 = $eq; 2132 } 2133 } 2134 2135 $eq2 = 0; 2136 $st = $steps; 2137 2138 for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) { 2139 $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st); 2140 if ($eq > $eq2) { 2141 $eq2 = $eq; 2142 } 2143 } 2144 2145 if ($eq1 > $eq2) { 2146 $equal += $eq1; 2147 } else if ($eq2 > 0) { 2148 $equal += $eq2; 2149 } 2150 } 2151 2152 return $equal; 2153} 2154 2155function generate_array_diff($ar1, $ar2, $is_reg, $w) 2156{ 2157 $idx1 = 0; $ofs1 = 0; $cnt1 = @count($ar1); 2158 $idx2 = 0; $ofs2 = 0; $cnt2 = @count($ar2); 2159 $diff = array(); 2160 $old1 = array(); 2161 $old2 = array(); 2162 2163 while ($idx1 < $cnt1 && $idx2 < $cnt2) { 2164 2165 if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { 2166 $idx1++; 2167 $idx2++; 2168 continue; 2169 } else { 2170 2171 $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1+1, $idx2, $cnt1, $cnt2, 10); 2172 $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2+1, $cnt1, $cnt2, 10); 2173 2174 if ($c1 > $c2) { 2175 $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++]; 2176 $last = 1; 2177 } else if ($c2 > 0) { 2178 $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++]; 2179 $last = 2; 2180 } else { 2181 $old1[$idx1] = sprintf("%03d- ", $idx1+1) . $w[$idx1++]; 2182 $old2[$idx2] = sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++]; 2183 } 2184 } 2185 } 2186 2187 reset($old1); $k1 = key($old1); $l1 = -2; 2188 reset($old2); $k2 = key($old2); $l2 = -2; 2189 2190 while ($k1 !== null || $k2 !== null) { 2191 2192 if ($k1 == $l1 + 1 || $k2 === null) { 2193 $l1 = $k1; 2194 $diff[] = current($old1); 2195 $k1 = next($old1) ? key($old1) : null; 2196 } else if ($k2 == $l2 + 1 || $k1 === null) { 2197 $l2 = $k2; 2198 $diff[] = current($old2); 2199 $k2 = next($old2) ? key($old2) : null; 2200 } else if ($k1 < $k2) { 2201 $l1 = $k1; 2202 $diff[] = current($old1); 2203 $k1 = next($old1) ? key($old1) : null; 2204 } else { 2205 $l2 = $k2; 2206 $diff[] = current($old2); 2207 $k2 = next($old2) ? key($old2) : null; 2208 } 2209 } 2210 2211 while ($idx1 < $cnt1) { 2212 $diff[] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; 2213 } 2214 2215 while ($idx2 < $cnt2) { 2216 $diff[] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; 2217 } 2218 2219 return $diff; 2220} 2221 2222function generate_diff($wanted, $wanted_re, $output) 2223{ 2224 $w = explode("\n", $wanted); 2225 $o = explode("\n", $output); 2226 $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re); 2227 $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w); 2228 2229 return implode("\r\n", $diff); 2230} 2231 2232function error($message) 2233{ 2234 echo "ERROR: {$message}\n"; 2235 exit(1); 2236} 2237 2238function settings2array($settings, &$ini_settings) 2239{ 2240 foreach($settings as $setting) { 2241 2242 if (strpos($setting, '=') !== false) { 2243 $setting = explode("=", $setting, 2); 2244 $name = trim($setting[0]); 2245 $value = trim($setting[1]); 2246 2247 if ($name == 'extension') { 2248 2249 if (!isset($ini_settings[$name])) { 2250 $ini_settings[$name] = array(); 2251 } 2252 2253 $ini_settings[$name][] = $value; 2254 2255 } else { 2256 $ini_settings[$name] = $value; 2257 } 2258 } 2259 } 2260} 2261 2262function settings2params(&$ini_settings) 2263{ 2264 $settings = ''; 2265 2266 foreach($ini_settings as $name => $value) { 2267 2268 if (is_array($value)) { 2269 foreach($value as $val) { 2270 $val = addslashes($val); 2271 $settings .= " -d \"$name=$val\""; 2272 } 2273 } else { 2274 if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value{0} == '"') { 2275 $len = strlen($value); 2276 2277 if ($value{$len - 1} == '"') { 2278 $value{0} = "'"; 2279 $value{$len - 1} = "'"; 2280 } 2281 } else { 2282 $value = addslashes($value); 2283 } 2284 2285 $settings .= " -d \"$name=$value\""; 2286 } 2287 } 2288 2289 $ini_settings = $settings; 2290} 2291 2292function compute_summary() 2293{ 2294 global $n_total, $test_results, $ignored_by_ext, $sum_results, $percent_results; 2295 2296 $n_total = count($test_results); 2297 $n_total += $ignored_by_ext; 2298 $sum_results = array( 2299 'PASSED' => 0, 2300 'WARNED' => 0, 2301 'SKIPPED' => 0, 2302 'FAILED' => 0, 2303 'BORKED' => 0, 2304 'LEAKED' => 0, 2305 'XFAILED' => 0 2306 ); 2307 2308 foreach ($test_results as $v) { 2309 $sum_results[$v]++; 2310 } 2311 2312 $sum_results['SKIPPED'] += $ignored_by_ext; 2313 $percent_results = array(); 2314 2315 while (list($v, $n) = each($sum_results)) { 2316 $percent_results[$v] = (100.0 * $n) / $n_total; 2317 } 2318} 2319 2320function get_summary($show_ext_summary, $show_html) 2321{ 2322 global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $leak_check; 2323 2324 $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED']; 2325 2326 if ($x_total) { 2327 $x_warned = (100.0 * $sum_results['WARNED']) / $x_total; 2328 $x_failed = (100.0 * $sum_results['FAILED']) / $x_total; 2329 $x_xfailed = (100.0 * $sum_results['XFAILED']) / $x_total; 2330 $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total; 2331 $x_passed = (100.0 * $sum_results['PASSED']) / $x_total; 2332 } else { 2333 $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = 0; 2334 } 2335 2336 $summary = ''; 2337 2338 if ($show_html) { 2339 $summary .= "<pre>\n"; 2340 } 2341 2342 if ($show_ext_summary) { 2343 $summary .= ' 2344===================================================================== 2345TEST RESULT SUMMARY 2346--------------------------------------------------------------------- 2347Exts skipped : ' . sprintf('%4d', $exts_skipped) . ' 2348Exts tested : ' . sprintf('%4d', $exts_tested) . ' 2349--------------------------------------------------------------------- 2350'; 2351 } 2352 2353 $summary .= ' 2354Number of tests : ' . sprintf('%4d', $n_total) . ' ' . sprintf('%8d', $x_total); 2355 2356 if ($sum_results['BORKED']) { 2357 $summary .= ' 2358Tests borked : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------'; 2359 } 2360 2361 $summary .= ' 2362Tests skipped : ' . sprintf('%4d (%5.1f%%)', $sum_results['SKIPPED'], $percent_results['SKIPPED']) . ' -------- 2363Tests warned : ' . sprintf('%4d (%5.1f%%)', $sum_results['WARNED'], $percent_results['WARNED']) . ' ' . sprintf('(%5.1f%%)', $x_warned) . ' 2364Tests failed : ' . sprintf('%4d (%5.1f%%)', $sum_results['FAILED'], $percent_results['FAILED']) . ' ' . sprintf('(%5.1f%%)', $x_failed) . ' 2365Expected fail : ' . sprintf('%4d (%5.1f%%)', $sum_results['XFAILED'], $percent_results['XFAILED']) . ' ' . sprintf('(%5.1f%%)', $x_xfailed); 2366 2367 if ($leak_check) { 2368 $summary .= ' 2369Tests leaked : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked); 2370 } 2371 2372 $summary .= ' 2373Tests passed : ' . sprintf('%4d (%5.1f%%)', $sum_results['PASSED'], $percent_results['PASSED']) . ' ' . sprintf('(%5.1f%%)', $x_passed) . ' 2374--------------------------------------------------------------------- 2375Time taken : ' . sprintf('%4d seconds', $end_time - $start_time) . ' 2376===================================================================== 2377'; 2378 $failed_test_summary = ''; 2379 2380 if (count($PHP_FAILED_TESTS['XFAILED'])) { 2381 $failed_test_summary .= ' 2382===================================================================== 2383EXPECTED FAILED TEST SUMMARY 2384--------------------------------------------------------------------- 2385'; 2386 foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) { 2387 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; 2388 } 2389 $failed_test_summary .= "=====================================================================\n"; 2390 } 2391 2392 if (count($PHP_FAILED_TESTS['BORKED'])) { 2393 $failed_test_summary .= ' 2394===================================================================== 2395BORKED TEST SUMMARY 2396--------------------------------------------------------------------- 2397'; 2398 foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) { 2399 $failed_test_summary .= $failed_test_data['info'] . "\n"; 2400 } 2401 2402 $failed_test_summary .= "=====================================================================\n"; 2403 } 2404 2405 if (count($PHP_FAILED_TESTS['FAILED'])) { 2406 $failed_test_summary .= ' 2407===================================================================== 2408FAILED TEST SUMMARY 2409--------------------------------------------------------------------- 2410'; 2411 foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) { 2412 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; 2413 } 2414 $failed_test_summary .= "=====================================================================\n"; 2415 } 2416 if (count($PHP_FAILED_TESTS['WARNED'])) { 2417 $failed_test_summary .= ' 2418===================================================================== 2419WARNED TEST SUMMARY 2420--------------------------------------------------------------------- 2421'; 2422 foreach ($PHP_FAILED_TESTS['WARNED'] as $failed_test_data) { 2423 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; 2424 } 2425 2426 $failed_test_summary .= "=====================================================================\n"; 2427 } 2428 2429 if (count($PHP_FAILED_TESTS['LEAKED'])) { 2430 $failed_test_summary .= ' 2431===================================================================== 2432LEAKED TEST SUMMARY 2433--------------------------------------------------------------------- 2434'; 2435 foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) { 2436 $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; 2437 } 2438 2439 $failed_test_summary .= "=====================================================================\n"; 2440 } 2441 2442 if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) { 2443 $summary .= $failed_test_summary; 2444 } 2445 2446 if ($show_html) { 2447 $summary .= "</pre>"; 2448 } 2449 2450 return $summary; 2451} 2452 2453function show_start($start_time) 2454{ 2455 global $html_output, $html_file; 2456 2457 if ($html_output) { 2458 fwrite($html_file, "<h2>Time Start: " . date('Y-m-d H:i:s', $start_time) . "</h2>\n"); 2459 fwrite($html_file, "<table>\n"); 2460 } 2461 2462 echo "TIME START " . date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n"; 2463} 2464 2465function show_end($end_time) 2466{ 2467 global $html_output, $html_file; 2468 2469 if ($html_output) { 2470 fwrite($html_file, "</table>\n"); 2471 fwrite($html_file, "<h2>Time End: " . date('Y-m-d H:i:s', $end_time) . "</h2>\n"); 2472 } 2473 2474 echo "=====================================================================\nTIME END " . date('Y-m-d H:i:s', $end_time) . "\n"; 2475} 2476 2477function show_summary() 2478{ 2479 global $html_output, $html_file; 2480 2481 if ($html_output) { 2482 fwrite($html_file, "<hr/>\n" . get_summary(true, true)); 2483 } 2484 2485 echo get_summary(true, false); 2486} 2487 2488function show_redirect_start($tests, $tested, $tested_file) 2489{ 2490 global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS; 2491 2492 if ($html_output) { 2493 fwrite($html_file, "<tr><td colspan='3'>---> $tests ($tested [$tested_file]) begin</td></tr>\n"); 2494 } 2495 2496 if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) { 2497 echo "REDIRECT $tests ($tested [$tested_file]) begin\n"; 2498 } else { 2499 // Write over the last line to avoid random trailing chars on next echo 2500 echo str_repeat(" ", $line_length), "\r"; 2501 } 2502} 2503 2504function show_redirect_ends($tests, $tested, $tested_file) 2505{ 2506 global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS; 2507 2508 if ($html_output) { 2509 fwrite($html_file, "<tr><td colspan='3'>---> $tests ($tested [$tested_file]) done</td></tr>\n"); 2510 } 2511 2512 if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) { 2513 echo "REDIRECT $tests ($tested [$tested_file]) done\n"; 2514 } else { 2515 // Write over the last line to avoid random trailing chars on next echo 2516 echo str_repeat(" ", $line_length), "\r"; 2517 } 2518} 2519 2520function show_test($test_idx, $shortname) 2521{ 2522 global $test_cnt; 2523 global $line_length; 2524 2525 $str = "TEST $test_idx/$test_cnt [$shortname]\r"; 2526 $line_length = strlen($str); 2527 echo $str; 2528 flush(); 2529} 2530 2531function show_result($result, $tested, $tested_file, $extra = '', $temp_filenames = null) 2532{ 2533 global $html_output, $html_file, $temp_target, $temp_urlbase, $line_length, $SHOW_ONLY_GROUPS; 2534 2535 if (!$SHOW_ONLY_GROUPS || in_array($result, $SHOW_ONLY_GROUPS)) { 2536 echo "$result $tested [$tested_file] $extra\n"; 2537 } else { 2538 // Write over the last line to avoid random trailing chars on next echo 2539 echo str_repeat(" ", $line_length), "\r"; 2540 } 2541 2542 if ($html_output) { 2543 2544 if (isset($temp_filenames['file']) && file_exists($temp_filenames['file'])) { 2545 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']); 2546 $tested = "<a href='$url'>$tested</a>"; 2547 } 2548 2549 if (isset($temp_filenames['skip']) && file_exists($temp_filenames['skip'])) { 2550 2551 if (empty($extra)) { 2552 $extra = "skipif"; 2553 } 2554 2555 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']); 2556 $extra = "<a href='$url'>$extra</a>"; 2557 2558 } else if (empty($extra)) { 2559 $extra = " "; 2560 } 2561 2562 if (isset($temp_filenames['diff']) && file_exists($temp_filenames['diff'])) { 2563 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']); 2564 $diff = "<a href='$url'>diff</a>"; 2565 } else { 2566 $diff = " "; 2567 } 2568 2569 if (isset($temp_filenames['mem']) && file_exists($temp_filenames['mem'])) { 2570 $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']); 2571 $mem = "<a href='$url'>leaks</a>"; 2572 } else { 2573 $mem = " "; 2574 } 2575 2576 fwrite($html_file, 2577 "<tr>" . 2578 "<td>$result</td>" . 2579 "<td>$tested</td>" . 2580 "<td>$extra</td>" . 2581 "<td>$diff</td>" . 2582 "<td>$mem</td>" . 2583 "</tr>\n"); 2584 } 2585} 2586 2587function junit_init() { 2588 // Check whether a junit log is wanted. 2589 $JUNIT = getenv('TEST_PHP_JUNIT'); 2590 if (empty($JUNIT)) { 2591 $JUNIT = FALSE; 2592 } elseif (!$fp = fopen($JUNIT, 'w')) { 2593 error("Failed to open $JUNIT for writing."); 2594 } else { 2595 $JUNIT = array( 2596 'fp' => $fp, 2597 'name' => 'php-src', 2598 'test_total' => 0, 2599 'test_pass' => 0, 2600 'test_fail' => 0, 2601 'test_error' => 0, 2602 'test_skip' => 0, 2603 'execution_time'=> 0, 2604 'suites' => array(), 2605 'files' => array() 2606 ); 2607 } 2608 2609 $GLOBALS['JUNIT'] = $JUNIT; 2610} 2611 2612function junit_save_xml() { 2613 global $JUNIT; 2614 if (!junit_enabled()) return; 2615 2616 $xml = '<?xml version="1.0" encoding="UTF-8"?>'. PHP_EOL . 2617 '<testsuites>' . PHP_EOL; 2618 $xml .= junit_get_suite_xml(); 2619 $xml .= '</testsuites>'; 2620 fwrite($JUNIT['fp'], $xml); 2621} 2622 2623function junit_get_suite_xml($suite_name = '') { 2624 global $JUNIT; 2625 2626 $suite = $suite_name ? $JUNIT['suites'][$suite_name] : $JUNIT; 2627 2628 $result = sprintf( 2629 '<testsuite name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL, 2630 $suite['name'], $suite['test_total'], $suite['test_fail'], $suite['test_error'], $suite['test_skip'], 2631 $suite['execution_time'] 2632 ); 2633 2634 foreach($suite['suites'] as $sub_suite) { 2635 $result .= junit_get_suite_xml($sub_suite['name']); 2636 } 2637 2638 // Output files only in subsuites 2639 if (!empty($suite_name)) { 2640 foreach($suite['files'] as $file) { 2641 $result .= $JUNIT['files'][$file]['xml']; 2642 } 2643 } 2644 2645 $result .= '</testsuite>' . PHP_EOL; 2646 2647 return $result; 2648} 2649 2650function junit_enabled() { 2651 global $JUNIT; 2652 return !empty($JUNIT); 2653} 2654 2655/** 2656 * @param array|string $type 2657 * @param string $file_name 2658 * @param string $test_name 2659 * @param int|string $time 2660 * @param string $message 2661 * @param string $details 2662 * @return void 2663 */ 2664function junit_mark_test_as($type, $file_name, $test_name, $time = null, $message = '', $details = '') { 2665 global $JUNIT; 2666 if (!junit_enabled()) return; 2667 2668 $suite = junit_get_suitename_for($file_name); 2669 2670 junit_suite_record($suite, 'test_total'); 2671 2672 $time = null !== $time ? $time : junit_get_timer($file_name); 2673 junit_suite_record($suite, 'execution_time', $time); 2674 2675 $escaped_details = htmlspecialchars($details, ENT_QUOTES, 'UTF-8'); 2676 2677 $escaped_test_name = basename($file_name) . ' - ' . htmlspecialchars($test_name, ENT_QUOTES); 2678 $JUNIT['files'][$file_name]['xml'] = "<testcase classname='$suite' name='$escaped_test_name' time='$time'>\n"; 2679 2680 if (is_array($type)) { 2681 $output_type = $type[0] . 'ED'; 2682 $temp = array_intersect(array('XFAIL', 'FAIL'), $type); 2683 $type = reset($temp); 2684 } else { 2685 $output_type = $type . 'ED'; 2686 } 2687 2688 if ('PASS' == $type || 'XFAIL' == $type) { 2689 junit_suite_record($suite, 'test_pass'); 2690 } elseif ('BORK' == $type) { 2691 junit_suite_record($suite, 'test_error'); 2692 $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$message'/>\n"; 2693 } elseif ('SKIP' == $type) { 2694 junit_suite_record($suite, 'test_skip'); 2695 $JUNIT['files'][$file_name]['xml'] .= "<skipped>$message</skipped>\n"; 2696 } elseif('FAIL' == $type) { 2697 junit_suite_record($suite, 'test_fail'); 2698 $JUNIT['files'][$file_name]['xml'] .= "<failure type='$output_type' message='$message'>$escaped_details</failure>\n"; 2699 } else { 2700 junit_suite_record($suite, 'test_error'); 2701 $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$message'>$escaped_details</error>\n"; 2702 } 2703 2704 $JUNIT['files'][$file_name]['xml'] .= "</testcase>\n"; 2705 2706} 2707 2708function junit_suite_record($suite, $param, $value = 1) { 2709 global $JUNIT; 2710 2711 $JUNIT[$param] += $value; 2712 $JUNIT['suites'][$suite][$param] += $value; 2713} 2714 2715function junit_get_timer($file_name) { 2716 global $JUNIT; 2717 if (!junit_enabled()) return 0; 2718 2719 if (isset($JUNIT['files'][$file_name]['total'])) { 2720 return number_format($JUNIT['files'][$file_name]['total'], 4); 2721 } 2722 2723 return 0; 2724} 2725 2726function junit_start_timer($file_name) { 2727 global $JUNIT; 2728 if (!junit_enabled()) return; 2729 2730 if (!isset($JUNIT['files'][$file_name]['start'])) { 2731 $JUNIT['files'][$file_name]['start'] = microtime(true); 2732 2733 $suite = junit_get_suitename_for($file_name); 2734 junit_init_suite($suite); 2735 $JUNIT['suites'][$suite]['files'][$file_name] = $file_name; 2736 } 2737} 2738 2739function junit_get_suitename_for($file_name) { 2740 return junit_path_to_classname(dirname($file_name)); 2741} 2742 2743function junit_path_to_classname($file_name) { 2744 global $JUNIT; 2745 return $JUNIT['name'] . '.' . str_replace(DIRECTORY_SEPARATOR, '.', $file_name); 2746} 2747 2748function junit_init_suite($suite_name) { 2749 global $JUNIT; 2750 if (!junit_enabled()) return; 2751 2752 if (!empty($JUNIT['suites'][$suite_name])) { 2753 return; 2754 } 2755 2756 $JUNIT['suites'][$suite_name] = array( 2757 'name' => $suite_name, 2758 'test_total' => 0, 2759 'test_pass' => 0, 2760 'test_fail' => 0, 2761 'test_error' => 0, 2762 'test_skip' => 0, 2763 'suites' => array(), 2764 'files' => array(), 2765 'execution_time'=> 0, 2766 ); 2767} 2768 2769function junit_finish_timer($file_name) { 2770 global $JUNIT; 2771 if (!junit_enabled()) return; 2772 2773 if (!isset($JUNIT['files'][$file_name]['start'])) { 2774 error("Timer for $file_name was not started!"); 2775 } 2776 2777 if (!isset($JUNIT['files'][$file_name]['total'])) { 2778 $JUNIT['files'][$file_name]['total'] = 0; 2779 } 2780 2781 $start = $JUNIT['files'][$file_name]['start']; 2782 $JUNIT['files'][$file_name]['total'] += microtime(true) - $start; 2783 unset($JUNIT['files'][$file_name]['start']); 2784} 2785 2786/* 2787 * Local variables: 2788 * tab-width: 4 2789 * c-basic-offset: 4 2790 * End: 2791 * vim: noet sw=4 ts=4 2792 */ 2793?> 2794