source: trunk/server/common/oursrc/php_scripts/test/run-tests.php @ 1137

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