Exemple #1
0
function run_test($php, $file, $env)
{
    global $log_format, $ini_overwrites, $cwd, $PHP_FAILED_TESTS;
    global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx;
    global $leak_check, $temp_source, $temp_target, $cfg, $environment;
    global $no_clean;
    global $valgrind_version;
    global $SHOW_ONLY_GROUPS;
    global $no_file_cache;
    $temp_filenames = null;
    $org_file = $file;
    if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) {
        $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
    }
    if (isset($env['TEST_PHPDBG_EXECUTABLE'])) {
        $phpdbg = $env['TEST_PHPDBG_EXECUTABLE'];
    }
    if (is_array($file)) {
        $file = $file[0];
    }
    if ($DETAILED) {
        echo "\n=================\nTEST {$file}\n";
    }
    // Load the sections of the test file.
    $section_text = array('TEST' => '');
    $fp = fopen($file, "rb") or error("Cannot open test file: {$file}");
    $borked = false;
    $bork_info = '';
    if (!feof($fp)) {
        $line = fgets($fp);
        if ($line === false) {
            $bork_info = "cannot read test";
            $borked = true;
        }
    } else {
        $bork_info = "empty test [{$file}]";
        $borked = true;
    }
    if (!$borked && strncmp('--TEST--', $line, 8)) {
        $bork_info = "tests must start with --TEST-- [{$file}]";
        $borked = true;
    }
    $section = 'TEST';
    $secfile = false;
    $secdone = false;
    while (!feof($fp)) {
        $line = fgets($fp);
        if ($line === false) {
            break;
        }
        // Match the beginning of a section.
        if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
            $section = $r[1];
            settype($section, 'string');
            if (isset($section_text[$section])) {
                $bork_info = "duplicated {$section} section";
                $borked = true;
            }
            $section_text[$section] = '';
            $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL';
            $secdone = false;
            continue;
        }
        // Add to the section text.
        if (!$secdone) {
            $section_text[$section] .= $line;
        }
        // End of actual test?
        if ($secfile && preg_match('/^===DONE===\\s*$/', $line)) {
            $secdone = true;
        }
    }
    // the redirect section allows a set of tests to be reused outside of
    // a given test dir
    if (!$borked) {
        if (@count($section_text['REDIRECTTEST']) == 1) {
            if ($IN_REDIRECT) {
                $borked = true;
                $bork_info = "Can't redirect a test from within a redirected test";
            } else {
                $borked = false;
            }
        } else {
            if (!isset($section_text['PHPDBG']) && @count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) {
                $bork_info = "missing section --FILE--";
                $borked = true;
            }
            if (@count($section_text['FILEEOF']) == 1) {
                $section_text['FILE'] = preg_replace("/[\r\n]+\$/", '', $section_text['FILEEOF']);
                unset($section_text['FILEEOF']);
            }
            foreach (array('FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX') as $prefix) {
                $key = $prefix . '_EXTERNAL';
                if (@count($section_text[$key]) == 1) {
                    // don't allow tests to retrieve files from anywhere but this subdirectory
                    $section_text[$key] = dirname($file) . '/' . trim(str_replace('..', '', $section_text[$key]));
                    if (file_exists($section_text[$key])) {
                        $section_text[$prefix] = file_get_contents($section_text[$key], FILE_BINARY);
                        unset($section_text[$key]);
                    } else {
                        $bork_info = "could not load --" . $key . "-- " . dirname($file) . '/' . trim($section_text[$key]);
                        $borked = true;
                    }
                }
            }
            if (@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX']) != 1) {
                $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
                $borked = true;
            }
        }
    }
    fclose($fp);
    $shortname = str_replace($cwd . '/', '', $file);
    $tested_file = $shortname;
    if ($borked) {
        show_result("BORK", $bork_info, $tested_file);
        $PHP_FAILED_TESTS['BORKED'][] = array('name' => $file, 'test_name' => '', 'output' => '', 'diff' => '', 'info' => "{$bork_info} [{$file}]");
        junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info);
        return 'BORKED';
    }
    if (isset($section_text['CAPTURE_STDIO'])) {
        $captureStdIn = stripos($section_text['CAPTURE_STDIO'], 'STDIN') !== false;
        $captureStdOut = stripos($section_text['CAPTURE_STDIO'], 'STDOUT') !== false;
        $captureStdErr = stripos($section_text['CAPTURE_STDIO'], 'STDERR') !== false;
    } else {
        $captureStdIn = true;
        $captureStdOut = true;
        $captureStdErr = true;
    }
    if ($captureStdOut && $captureStdErr) {
        $cmdRedirect = ' 2>&1';
    } else {
        $cmdRedirect = '';
    }
    $tested = trim($section_text['TEST']);
    /* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */
    if (!empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['GZIP_POST']) || !empty($section_text['DEFLATE_POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['PUT']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) {
        if (isset($php_cgi)) {
            $old_php = $php;
            $php = $php_cgi . ' -C ';
        } else {
            if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) {
                $old_php = $php;
                $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C ';
            } else {
                if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) {
                    $old_php = $php;
                    $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C ';
                } else {
                    if (file_exists("./sapi/cgi/php-cgi")) {
                        $old_php = $php;
                        $php = realpath("./sapi/cgi/php-cgi") . ' -C ';
                    } else {
                        if (file_exists(dirname($php) . "/php-cgi")) {
                            $old_php = $php;
                            $php = realpath(dirname($php) . "/php-cgi") . ' -C ';
                        } else {
                            show_result('SKIP', $tested, $tested_file, "reason: CGI not available");
                            junit_init_suite(junit_get_suitename_for($shortname));
                            junit_mark_test_as('SKIP', $shortname, $tested, 0, 'CGI not available');
                            return 'SKIPPED';
                        }
                    }
                }
            }
        }
        $uses_cgi = true;
    }
    /* For phpdbg tests, check if phpdbg sapi is available and if it is, use it. */
    if (array_key_exists('PHPDBG', $section_text)) {
        if (!isset($section_text['STDIN'])) {
            $section_text['STDIN'] = $section_text['PHPDBG'] . "\n";
        }
        if (isset($phpdbg)) {
            $old_php = $php;
            $php = $phpdbg . ' -qIb';
        } else {
            show_result('SKIP', $tested, $tested_file, "reason: phpdbg not available");
            junit_init_suite(junit_get_suitename_for($shortname));
            junit_mark_test_as('SKIP', $shortname, $tested, 0, 'phpdbg not available');
            return 'SKIPPED';
        }
    }
    if (!$SHOW_ONLY_GROUPS) {
        show_test($test_idx, $shortname);
    }
    if (is_array($IN_REDIRECT)) {
        $temp_dir = $test_dir = $IN_REDIRECT['dir'];
    } else {
        $temp_dir = $test_dir = realpath(dirname($file));
    }
    if ($temp_source && $temp_target) {
        $temp_dir = str_replace($temp_source, $temp_target, $temp_dir);
    }
    $main_file_name = basename($file, 'phpt');
    $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff';
    $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log';
    $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp';
    $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out';
    $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem';
    $sh_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'sh';
    $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
    $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
    $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
    $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
    $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
    $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
    $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.');
    $tmp_relative_file = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $test_file) . 't';
    if ($temp_source && $temp_target) {
        $temp_skipif .= 's';
        $temp_file .= 's';
        $temp_clean .= 's';
        $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps';
        if (!is_dir(dirname($copy_file))) {
            mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file));
        }
        if (isset($section_text['FILE'])) {
            save_text($copy_file, $section_text['FILE']);
        }
        $temp_filenames = array('file' => $copy_file, 'diff' => $diff_filename, 'log' => $log_filename, 'exp' => $exp_filename, 'out' => $output_filename, 'mem' => $memcheck_filename, 'sh' => $sh_filename, 'php' => $temp_file, 'skip' => $temp_skipif, 'clean' => $temp_clean);
    }
    if (is_array($IN_REDIRECT)) {
        $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']);
        $tested_file = $tmp_relative_file;
    }
    // unlink old test results
    @unlink($diff_filename);
    @unlink($log_filename);
    @unlink($exp_filename);
    @unlink($output_filename);
    @unlink($memcheck_filename);
    @unlink($sh_filename);
    @unlink($temp_file);
    @unlink($test_file);
    @unlink($temp_skipif);
    @unlink($test_skipif);
    @unlink($tmp_post);
    @unlink($temp_clean);
    @unlink($test_clean);
    // Reset environment from any previous test.
    $env['REDIRECT_STATUS'] = '';
    $env['QUERY_STRING'] = '';
    $env['PATH_TRANSLATED'] = '';
    $env['SCRIPT_FILENAME'] = '';
    $env['REQUEST_METHOD'] = '';
    $env['CONTENT_TYPE'] = '';
    $env['CONTENT_LENGTH'] = '';
    $env['TZ'] = '';
    if (!empty($section_text['ENV'])) {
        foreach (explode("\n", trim($section_text['ENV'])) as $e) {
            $e = explode('=', trim($e), 2);
            if (!empty($e[0]) && isset($e[1])) {
                $env[$e[0]] = $e[1];
            }
        }
    }
    // Default ini settings
    $ini_settings = array();
    // Additional required extensions
    if (array_key_exists('EXTENSIONS', $section_text)) {
        $ext_dir = `{$php} -r 'echo ini_get("extension_dir");'`;
        $extensions = preg_split("/[\n\r]+/", trim($section_text['EXTENSIONS']));
        $loaded = explode(",", `{$php} -n -r 'echo implode(",", get_loaded_extensions());'`);
        foreach ($extensions as $req_ext) {
            if (!in_array($req_ext, $loaded)) {
                if ($req_ext == 'opcache') {
                    $ini_settings['zend_extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $req_ext . '.' . PHP_SHLIB_SUFFIX;
                } else {
                    $ini_settings['extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $req_ext . '.' . PHP_SHLIB_SUFFIX;
                }
            }
        }
    }
    // additional ini overwrites
    //$ini_overwrites[] = 'setting=value';
    settings2array($ini_overwrites, $ini_settings);
    // Any special ini settings
    // these may overwrite the test defaults...
    if (array_key_exists('INI', $section_text)) {
        if (strpos($section_text['INI'], '{PWD}') !== false) {
            $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
        }
        settings2array(preg_split("/[\n\r]+/", $section_text['INI']), $ini_settings);
    }
    settings2params($ini_settings);
    // Check if test should be skipped.
    $info = '';
    $warn = false;
    if (array_key_exists('SKIPIF', $section_text)) {
        if (trim($section_text['SKIPIF'])) {
            show_file_block('skip', $section_text['SKIPIF']);
            save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif);
            $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
            if ($leak_check) {
                $env['USE_ZEND_ALLOC'] = '0';
                $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
            } else {
                $env['USE_ZEND_ALLOC'] = '1';
                $env['ZEND_DONT_UNLOAD_MODULES'] = 0;
            }
            junit_start_timer($shortname);
            $output = system_with_timeout("{$extra} {$php} {$pass_options} -q {$ini_settings} {$no_file_cache} -d display_errors=0 \"{$test_skipif}\"", $env);
            junit_finish_timer($shortname);
            if (!$cfg['keep']['skip']) {
                @unlink($test_skipif);
            }
            if (!strncasecmp('skip', ltrim($output), 4)) {
                if (preg_match('/^\\s*skip\\s*(.+)\\s*/i', $output, $m)) {
                    show_result('SKIP', $tested, $tested_file, "reason: {$m['1']}", $temp_filenames);
                } else {
                    show_result('SKIP', $tested, $tested_file, '', $temp_filenames);
                }
                if (!$cfg['keep']['skip']) {
                    @unlink($test_skipif);
                }
                $message = !empty($m[1]) ? $m[1] : '';
                junit_mark_test_as('SKIP', $shortname, $tested, null, $message);
                return 'SKIPPED';
            }
            if (!strncasecmp('info', ltrim($output), 4)) {
                if (preg_match('/^\\s*info\\s*(.+)\\s*/i', $output, $m)) {
                    $info = " (info: {$m['1']})";
                }
            }
            if (!strncasecmp('warn', ltrim($output), 4)) {
                if (preg_match('/^\\s*warn\\s*(.+)\\s*/i', $output, $m)) {
                    $warn = true;
                    /* only if there is a reason */
                    $info = " (warn: {$m['1']})";
                }
            }
        }
    }
    if (!extension_loaded("zlib") && (array_key_exists("GZIP_POST", $section_text) || array_key_exists("DEFLATE_POST", $section_text))) {
        $message = "ext/zlib required";
        show_result('SKIP', $tested, $tested_file, "reason: {$message}", $temp_filenames);
        junit_mark_test_as('SKIP', $shortname, $tested, null, $message);
        return 'SKIPPED';
    }
    if (@count($section_text['REDIRECTTEST']) == 1) {
        $test_files = array();
        $IN_REDIRECT = eval($section_text['REDIRECTTEST']);
        $IN_REDIRECT['via'] = "via [{$shortname}]\n\t";
        $IN_REDIRECT['dir'] = realpath(dirname($file));
        $IN_REDIRECT['prefix'] = trim($section_text['TEST']);
        if (!empty($IN_REDIRECT['TESTS'])) {
            if (is_array($org_file)) {
                $test_files[] = $org_file[1];
            } else {
                $GLOBALS['test_files'] = $test_files;
                find_files($IN_REDIRECT['TESTS']);
                foreach ($GLOBALS['test_files'] as $f) {
                    $test_files[] = array($f, $file);
                }
            }
            $test_cnt += @count($test_files) - 1;
            $test_idx--;
            show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file);
            // set up environment
            $redirenv = array_merge($environment, $IN_REDIRECT['ENV']);
            $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR;
            usort($test_files, "test_sort");
            run_all_tests($test_files, $redirenv, $tested);
            show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file);
            // a redirected test never fails
            $IN_REDIRECT = false;
            junit_mark_test_as('PASS', $shortname, $tested);
            return 'REDIR';
        } else {
            $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory.";
            show_result("BORK", $bork_info, '', $temp_filenames);
            $PHP_FAILED_TESTS['BORKED'][] = array('name' => $file, 'test_name' => '', 'output' => '', 'diff' => '', 'info' => "{$bork_info} [{$file}]");
        }
    }
    if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) {
        if (is_array($org_file)) {
            $file = $org_file[0];
        }
        $bork_info = "Redirected test did not contain redirection info";
        show_result("BORK", $bork_info, '', $temp_filenames);
        $PHP_FAILED_TESTS['BORKED'][] = array('name' => $file, 'test_name' => '', 'output' => '', 'diff' => '', 'info' => "{$bork_info} [{$file}]");
        junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info);
        return 'BORKED';
    }
    // We've satisfied the preconditions - run the test!
    if (isset($section_text['FILE'])) {
        show_file_block('php', $section_text['FILE'], 'TEST');
        save_text($test_file, $section_text['FILE'], $temp_file);
    } else {
        $test_file = $temp_file = "";
    }
    if (array_key_exists('GET', $section_text)) {
        $query_string = trim($section_text['GET']);
    } else {
        $query_string = '';
    }
    $env['REDIRECT_STATUS'] = '1';
    if (empty($env['QUERY_STRING'])) {
        $env['QUERY_STRING'] = $query_string;
    }
    if (empty($env['PATH_TRANSLATED'])) {
        $env['PATH_TRANSLATED'] = $test_file;
    }
    if (empty($env['SCRIPT_FILENAME'])) {
        $env['SCRIPT_FILENAME'] = $test_file;
    }
    if (array_key_exists('COOKIE', $section_text)) {
        $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
    } else {
        $env['HTTP_COOKIE'] = '';
    }
    $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : '';
    if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
        $post = trim($section_text['POST_RAW']);
        $raw_lines = explode("\n", $post);
        $request = '';
        $started = false;
        foreach ($raw_lines as $line) {
            if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
                $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
                continue;
            }
            if ($started) {
                $request .= "\n";
            }
            $started = true;
            $request .= $line;
        }
        $env['CONTENT_LENGTH'] = strlen($request);
        $env['REQUEST_METHOD'] = 'POST';
        if (empty($request)) {
            junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request');
            return 'BORKED';
        }
        save_text($tmp_post, $request);
        $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\"{$cmdRedirect} < \"{$tmp_post}\"";
    } elseif (array_key_exists('PUT', $section_text) && !empty($section_text['PUT'])) {
        $post = trim($section_text['PUT']);
        $raw_lines = explode("\n", $post);
        $request = '';
        $started = false;
        foreach ($raw_lines as $line) {
            if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
                $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
                continue;
            }
            if ($started) {
                $request .= "\n";
            }
            $started = true;
            $request .= $line;
        }
        $env['CONTENT_LENGTH'] = strlen($request);
        $env['REQUEST_METHOD'] = 'PUT';
        if (empty($request)) {
            junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request');
            return 'BORKED';
        }
        save_text($tmp_post, $request);
        $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\"{$cmdRedirect} < \"{$tmp_post}\"";
    } else {
        if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
            $post = trim($section_text['POST']);
            $content_length = strlen($post);
            save_text($tmp_post, $post);
            $env['REQUEST_METHOD'] = 'POST';
            if (empty($env['CONTENT_TYPE'])) {
                $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
            }
            if (empty($env['CONTENT_LENGTH'])) {
                $env['CONTENT_LENGTH'] = $content_length;
            }
            $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\"{$cmdRedirect} < \"{$tmp_post}\"";
        } else {
            if (array_key_exists('GZIP_POST', $section_text) && !empty($section_text['GZIP_POST'])) {
                $post = trim($section_text['GZIP_POST']);
                $post = gzencode($post, 9, FORCE_GZIP);
                $env['HTTP_CONTENT_ENCODING'] = 'gzip';
                save_text($tmp_post, $post);
                $content_length = strlen($post);
                $env['REQUEST_METHOD'] = 'POST';
                $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
                $env['CONTENT_LENGTH'] = $content_length;
                $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\"{$cmdRedirect} < \"{$tmp_post}\"";
            } else {
                if (array_key_exists('DEFLATE_POST', $section_text) && !empty($section_text['DEFLATE_POST'])) {
                    $post = trim($section_text['DEFLATE_POST']);
                    $post = gzcompress($post, 9);
                    $env['HTTP_CONTENT_ENCODING'] = 'deflate';
                    save_text($tmp_post, $post);
                    $content_length = strlen($post);
                    $env['REQUEST_METHOD'] = 'POST';
                    $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
                    $env['CONTENT_LENGTH'] = $content_length;
                    $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\"{$cmdRedirect} < \"{$tmp_post}\"";
                } else {
                    $env['REQUEST_METHOD'] = 'GET';
                    $env['CONTENT_TYPE'] = '';
                    $env['CONTENT_LENGTH'] = '';
                    $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\" {$args}{$cmdRedirect}";
                }
            }
        }
    }
    if ($leak_check) {
        $env['USE_ZEND_ALLOC'] = '0';
        $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
        /* --vex-iropt-register-updates=allregs-at-mem-access is necessary for phpdbg watchpoint tests */
        if (version_compare($valgrind_version, '3.8.0', '>=')) {
            /* valgrind 3.3.0+ doesn't have --log-file-exactly option */
            $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-register-updates=allregs-at-mem-access --log-file={$memcheck_filename} {$cmd}";
        } elseif (version_compare($valgrind_version, '3.3.0', '>=')) {
            $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-precise-memory-exns=yes --log-file={$memcheck_filename} {$cmd}";
        } else {
            $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-precise-memory-exns=yes --log-file-exactly={$memcheck_filename} {$cmd}";
        }
    } else {
        $env['USE_ZEND_ALLOC'] = '1';
        $env['ZEND_DONT_UNLOAD_MODULES'] = 0;
    }
    if ($DETAILED) {
        echo "\nCONTENT_LENGTH  = " . $env['CONTENT_LENGTH'] . "\nCONTENT_TYPE    = " . $env['CONTENT_TYPE'] . "\nPATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . "\nQUERY_STRING    = " . $env['QUERY_STRING'] . "\nREDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . "\nREQUEST_METHOD  = " . $env['REQUEST_METHOD'] . "\nSCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . "\nHTTP_COOKIE     = " . $env['HTTP_COOKIE'] . "\nCOMMAND {$cmd}\n";
    }
    junit_start_timer($shortname);
    $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null, $captureStdIn, $captureStdOut, $captureStdErr);
    junit_finish_timer($shortname);
    if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) {
        if (trim($section_text['CLEAN'])) {
            show_file_block('clean', $section_text['CLEAN']);
            save_text($test_clean, trim($section_text['CLEAN']), $temp_clean);
            if (!$no_clean) {
                $clean_params = array();
                settings2array($ini_overwrites, $clean_params);
                settings2params($clean_params);
                $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
                system_with_timeout("{$extra} {$php} {$pass_options} -q {$clean_params} {$no_file_cache} \"{$test_clean}\"", $env);
            }
            if (!$cfg['keep']['clean']) {
                @unlink($test_clean);
            }
        }
    }
    @unlink($tmp_post);
    $leaked = false;
    $passed = false;
    if ($leak_check) {
        // leak check
        $leaked = filesize($memcheck_filename) > 0;
        if (!$leaked) {
            @unlink($memcheck_filename);
        }
    }
    // Does the output match what is expected?
    $output = preg_replace("/\r\n/", "\n", trim($out));
    /* when using CGI, strip the headers from the output */
    $headers = array();
    if (!empty($uses_cgi) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
        $output = trim($match[2]);
        $rh = preg_split("/[\n\r]+/", $match[1]);
        foreach ($rh as $line) {
            if (strpos($line, ':') !== false) {
                $line = explode(':', $line, 2);
                $headers[trim($line[0])] = trim($line[1]);
            }
        }
    }
    $failed_headers = false;
    if (isset($section_text['EXPECTHEADERS'])) {
        $want = array();
        $wanted_headers = array();
        $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']);
        foreach ($lines as $line) {
            if (strpos($line, ':') !== false) {
                $line = explode(':', $line, 2);
                $want[trim($line[0])] = trim($line[1]);
                $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]);
            }
        }
        $output_headers = array();
        foreach ($want as $k => $v) {
            if (isset($headers[$k])) {
                $output_headers[] = $k . ': ' . $headers[$k];
            }
            if (!isset($headers[$k]) || $headers[$k] != $v) {
                $failed_headers = true;
            }
        }
        ksort($wanted_headers);
        $wanted_headers = implode("\n", $wanted_headers);
        ksort($output_headers);
        $output_headers = implode("\n", $output_headers);
    }
    show_file_block('out', $output);
    if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
        if (isset($section_text['EXPECTF'])) {
            $wanted = trim($section_text['EXPECTF']);
        } else {
            $wanted = trim($section_text['EXPECTREGEX']);
        }
        show_file_block('exp', $wanted);
        $wanted_re = preg_replace('/\\r\\n/', "\n", $wanted);
        if (isset($section_text['EXPECTF'])) {
            // do preg_quote, but miss out any %r delimited sections
            $temp = "";
            $r = "%r";
            $startOffset = 0;
            $length = strlen($wanted_re);
            while ($startOffset < $length) {
                $start = strpos($wanted_re, $r, $startOffset);
                if ($start !== false) {
                    // we have found a start tag
                    $end = strpos($wanted_re, $r, $start + 2);
                    if ($end === false) {
                        // unbalanced tag, ignore it.
                        $end = $start = $length;
                    }
                } else {
                    // no more %r sections
                    $start = $end = $length;
                }
                // quote a non re portion of the string
                $temp = $temp . preg_quote(substr($wanted_re, $startOffset, $start - $startOffset), '/');
                // add the re unquoted.
                if ($end > $start) {
                    $temp = $temp . '(' . substr($wanted_re, $start + 2, $end - $start - 2) . ')';
                }
                $startOffset = $end + 2;
            }
            $wanted_re = $temp;
            $wanted_re = str_replace(array('%binary_string_optional%'), 'string', $wanted_re);
            $wanted_re = str_replace(array('%unicode_string_optional%'), 'string', $wanted_re);
            $wanted_re = str_replace(array('%unicode\\|string%', '%string\\|unicode%'), 'string', $wanted_re);
            $wanted_re = str_replace(array('%u\\|b%', '%b\\|u%'), '', $wanted_re);
            // Stick to basics
            $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re);
            $wanted_re = str_replace('%s', '[^\\r\\n]+', $wanted_re);
            $wanted_re = str_replace('%S', '[^\\r\\n]*', $wanted_re);
            $wanted_re = str_replace('%a', '.+', $wanted_re);
            $wanted_re = str_replace('%A', '.*', $wanted_re);
            $wanted_re = str_replace('%w', '\\s*', $wanted_re);
            $wanted_re = str_replace('%i', '[+-]?\\d+', $wanted_re);
            $wanted_re = str_replace('%d', '\\d+', $wanted_re);
            $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re);
            $wanted_re = str_replace('%f', '[+-]?\\.?\\d+\\.?\\d*(?:[Ee][+-]?\\d+)?', $wanted_re);
            $wanted_re = str_replace('%c', '.', $wanted_re);
            // %f allows two points "-.0.0" but that is the best *simple* expression
        }
        /* DEBUG YOUR REGEX HERE
        		var_dump($wanted_re);
        		print(str_repeat('=', 80) . "\n");
        		var_dump($output);
        */
        if (preg_match("/^{$wanted_re}\$/s", $output)) {
            $passed = true;
            if (!$cfg['keep']['php']) {
                @unlink($test_file);
            }
            if (!$leaked && !$failed_headers) {
                if (isset($section_text['XFAIL'])) {
                    $warn = true;
                    $info = " (warn: XFAIL section but test passes)";
                } else {
                    show_result("PASS", $tested, $tested_file, '', $temp_filenames);
                    junit_mark_test_as('PASS', $shortname, $tested);
                    return 'PASSED';
                }
            }
        }
    } else {
        $wanted = trim($section_text['EXPECT']);
        $wanted = preg_replace('/\\r\\n/', "\n", $wanted);
        show_file_block('exp', $wanted);
        // compare and leave on success
        if (!strcmp($output, $wanted)) {
            $passed = true;
            if (!$cfg['keep']['php']) {
                @unlink($test_file);
            }
            if (!$leaked && !$failed_headers) {
                if (isset($section_text['XFAIL'])) {
                    $warn = true;
                    $info = " (warn: XFAIL section but test passes)";
                } else {
                    show_result("PASS", $tested, $tested_file, '', $temp_filenames);
                    junit_mark_test_as('PASS', $shortname, $tested);
                    return 'PASSED';
                }
            }
        }
        $wanted_re = null;
    }
    // Test failed so we need to report details.
    if ($failed_headers) {
        $passed = false;
        $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted;
        $output = $output_headers . "\n--HEADERS--\n" . $output;
        if (isset($wanted_re)) {
            $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re;
        }
    }
    if ($leaked) {
        $restype[] = 'LEAK';
    }
    if ($warn) {
        $restype[] = 'WARN';
    }
    if (!$passed) {
        if (isset($section_text['XFAIL'])) {
            $restype[] = 'XFAIL';
            $info = '  XFAIL REASON: ' . rtrim($section_text['XFAIL']);
        } else {
            $restype[] = 'FAIL';
        }
    }
    if (!$passed) {
        // write .exp
        if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, $wanted, FILE_BINARY) === false) {
            error("Cannot create expected test output - {$exp_filename}");
        }
        // write .out
        if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) {
            error("Cannot create test output - {$output_filename}");
        }
        // write .diff
        $diff = generate_diff($wanted, $wanted_re, $output);
        if (is_array($IN_REDIRECT)) {
            $diff = "# original source file: {$shortname}\n" . $diff;
        }
        show_file_block('diff', $diff);
        if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, $diff, FILE_BINARY) === false) {
            error("Cannot create test diff - {$diff_filename}");
        }
        // write .sh
        if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh\n\n{$cmd}\n", FILE_BINARY) === false) {
            error("Cannot create test shell script - {$sh_filename}");
        }
        chmod($sh_filename, 0755);
        // write .log
        if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, "\n---- EXPECTED OUTPUT\n{$wanted}\n---- ACTUAL OUTPUT\n{$output}\n---- FAILED\n", FILE_BINARY) === false) {
            error("Cannot create test log - {$log_filename}");
            error_report($file, $log_filename, $tested);
        }
    }
    show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames);
    foreach ($restype as $type) {
        $PHP_FAILED_TESTS[$type . 'ED'][] = array('name' => $file, 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [{$tested_file}]", 'output' => $output_filename, 'diff' => $diff_filename, 'info' => $info);
    }
    $diff = empty($diff) ? '' : preg_replace('/\\e/', '<esc>', $diff);
    junit_mark_test_as($restype, str_replace($cwd . '/', '', $tested_file), $tested, null, $info, $diff);
    return $restype[0] . 'ED';
}
Exemple #2
0
function run_test($php, $file, $env)
{
    global $log_format, $info_params, $ini_overwrites, $cwd, $PHP_FAILED_TESTS;
    global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx;
    global $leak_check, $temp_source, $temp_target, $cfg, $environment;
    global $no_clean;
    global $valgrind_version;
    $temp_filenames = null;
    $org_file = $file;
    if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) {
        $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
    }
    if (is_array($file)) {
        $file = $file[0];
    }
    if ($DETAILED) {
        echo "\n=================\nTEST {$file}\n";
    }
    // Load the sections of the test file.
    $section_text = array('TEST' => '');
    $fp = fopen($file, "rt") or error("Cannot open test file: {$file}");
    $borked = false;
    $bork_info = '';
    if (!feof($fp)) {
        $line = fgets($fp);
        if ($line === false) {
            $bork_info = "cannot read test";
            $borked = true;
        }
    } else {
        $bork_info = "empty test [{$file}]";
        $borked = true;
    }
    if (!$borked && strncmp('--TEST--', $line, 8)) {
        $bork_info = "tests must start with --TEST-- [{$file}]";
        $borked = true;
    }
    $section = 'TEST';
    $secfile = false;
    $secdone = false;
    while (!feof($fp)) {
        $line = fgets($fp);
        // Match the beginning of a section.
        if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
            $section = $r[1];
            if (isset($section_text[$section])) {
                $bork_info = "duplicated {$section} section";
                $borked = true;
            }
            $section_text[$section] = '';
            $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL';
            $secdone = false;
            continue;
        }
        // Add to the section text.
        if (!$secdone) {
            $section_text[$section] .= $line;
        }
        // End of actual test?
        if ($secfile && preg_match('/^===DONE===\\s*$/', $line)) {
            $secdone = true;
        }
    }
    // the redirect section allows a set of tests to be reused outside of
    // a given test dir
    if (!$borked) {
        if (@count($section_text['REDIRECTTEST']) == 1) {
            if ($IN_REDIRECT) {
                $borked = true;
                $bork_info = "Can't redirect a test from within a redirected test";
            } else {
                $borked = false;
            }
        } else {
            if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) {
                $bork_info = "missing section --FILE--";
                $borked = true;
            }
            if (@count($section_text['FILEEOF']) == 1) {
                $section_text['FILE'] = preg_replace("/[\r\n]+\$/", '', $section_text['FILEEOF']);
                unset($section_text['FILEEOF']);
            }
            if (@count($section_text['FILE_EXTERNAL']) == 1) {
                // don't allow tests to retrieve files from anywhere but this subdirectory
                $section_text['FILE_EXTERNAL'] = dirname($file) . '/' . trim(str_replace('..', '', $section_text['FILE_EXTERNAL']));
                if (file_exists($section_text['FILE_EXTERNAL'])) {
                    $section_text['FILE'] = file_get_contents($section_text['FILE_EXTERNAL']);
                    unset($section_text['FILE_EXTERNAL']);
                } else {
                    $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']);
                    $borked = true;
                }
            }
            if (@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX']) != 1) {
                $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
                $borked = true;
            }
        }
    }
    fclose($fp);
    $shortname = str_replace($cwd . '/', '', $file);
    $tested_file = $shortname;
    if ($borked) {
        show_result("BORK", $bork_info, $tested_file);
        $PHP_FAILED_TESTS['BORKED'][] = array('name' => $file, 'test_name' => '', 'output' => '', 'diff' => '', 'info' => "{$bork_info} [{$file}]");
        return 'BORKED';
    }
    $tested = trim($section_text['TEST']);
    /* For GET/POST tests, check if cgi sapi is available and if it is, use it. */
    if (!empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) {
        if (isset($php_cgi)) {
            $old_php = $php;
            $php = $php_cgi . ' -C ';
        } else {
            if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) {
                $old_php = $php;
                $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C ';
            } else {
                if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) {
                    $old_php = $php;
                    $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C ';
                } else {
                    if (file_exists("./sapi/cgi/php-cgi")) {
                        $old_php = $php;
                        $php = realpath("./sapi/cgi/php-cgi") . ' -C ';
                    } else {
                        show_result('SKIP', $tested, $tested_file, "reason: CGI not available");
                        return 'SKIPPED';
                    }
                }
            }
        }
    }
    show_test($test_idx, $shortname);
    if (is_array($IN_REDIRECT)) {
        $temp_dir = $test_dir = $IN_REDIRECT['dir'];
    } else {
        $temp_dir = $test_dir = realpath(dirname($file));
    }
    if ($temp_source && $temp_target) {
        $temp_dir = str_replace($temp_source, $temp_target, $temp_dir);
    }
    $main_file_name = basename($file, 'phpt');
    $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff';
    $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log';
    $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp';
    $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out';
    $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem';
    $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
    $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
    $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
    $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
    $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
    $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
    $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.');
    $tmp_relative_file = str_replace(realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR, '', $test_file) . 't';
    if ($temp_source && $temp_target) {
        $temp_skipif .= 's';
        $temp_file .= 's';
        $temp_clean .= 's';
        $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps';
        if (!is_dir(dirname($copy_file))) {
            mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file));
        }
        if (isset($section_text['FILE'])) {
            save_text($copy_file, $section_text['FILE']);
        }
        $temp_filenames = array('file' => $copy_file, 'diff' => $diff_filename, 'log' => $log_filename, 'exp' => $exp_filename, 'out' => $output_filename, 'mem' => $memcheck_filename, 'php' => $temp_file, 'skip' => $temp_skipif, 'clean' => $temp_clean);
    }
    if (is_array($IN_REDIRECT)) {
        $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']);
        $tested_file = $tmp_relative_file;
        $section_text['FILE'] = "# original source file: {$shortname}\n" . $section_text['FILE'];
    }
    // unlink old test results
    @unlink($diff_filename);
    @unlink($log_filename);
    @unlink($exp_filename);
    @unlink($output_filename);
    @unlink($memcheck_filename);
    @unlink($temp_file);
    @unlink($test_file);
    @unlink($temp_skipif);
    @unlink($test_skipif);
    @unlink($tmp_post);
    @unlink($temp_clean);
    @unlink($test_clean);
    // Reset environment from any previous test.
    $env['REDIRECT_STATUS'] = '';
    $env['QUERY_STRING'] = '';
    $env['PATH_TRANSLATED'] = '';
    $env['SCRIPT_FILENAME'] = '';
    $env['REQUEST_METHOD'] = '';
    $env['CONTENT_TYPE'] = '';
    $env['CONTENT_LENGTH'] = '';
    if (!empty($section_text['ENV'])) {
        foreach (explode("\n", trim($section_text['ENV'])) as $e) {
            $e = explode('=', trim($e), 2);
            if (!empty($e[0]) && isset($e[1])) {
                $env[$e[0]] = $e[1];
            }
        }
    }
    // Default ini settings
    $ini_settings = array();
    // additional ini overwrites
    //$ini_overwrites[] = 'setting=value';
    settings2array($ini_overwrites, $ini_settings);
    // Any special ini settings
    // these may overwrite the test defaults...
    if (array_key_exists('INI', $section_text)) {
        if (strpos($section_text['INI'], '{PWD}') !== false) {
            $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
        }
        settings2array(preg_split("/[\n\r]+/", $section_text['INI']), $ini_settings);
    }
    settings2params($ini_settings);
    // Check if test should be skipped.
    $info = '';
    $warn = false;
    if (array_key_exists('SKIPIF', $section_text)) {
        if (trim($section_text['SKIPIF'])) {
            show_file_block('skip', $section_text['SKIPIF']);
            save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif);
            $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
            if ($leak_check) {
                $env['USE_ZEND_ALLOC'] = '0';
            } else {
                $env['USE_ZEND_ALLOC'] = '1';
            }
            $output = system_with_timeout("{$extra} {$php} {$pass_options} -q {$ini_settings} {$test_skipif}", $env);
            if (!$cfg['keep']['skip']) {
                @unlink($test_skipif);
            }
            if (!strncasecmp('skip', ltrim($output), 4)) {
                if (preg_match('/^\\s*skip\\s*(.+)\\s*/i', $output, $m)) {
                    show_result('SKIP', $tested, $tested_file, "reason: {$m['1']}", $temp_filenames);
                } else {
                    show_result('SKIP', $tested, $tested_file, '', $temp_filenames);
                }
                if (isset($old_php)) {
                    $php = $old_php;
                }
                if (!$cfg['keep']['skip']) {
                    @unlink($test_skipif);
                }
                return 'SKIPPED';
            }
            if (!strncasecmp('info', ltrim($output), 4)) {
                if (preg_match('/^\\s*info\\s*(.+)\\s*/i', $output, $m)) {
                    $info = " (info: {$m['1']})";
                }
            }
            if (!strncasecmp('warn', ltrim($output), 4)) {
                if (preg_match('/^\\s*warn\\s*(.+)\\s*/i', $output, $m)) {
                    $warn = true;
                    /* only if there is a reason */
                    $info = " (warn: {$m['1']})";
                }
            }
        }
    }
    if (@count($section_text['REDIRECTTEST']) == 1) {
        $test_files = array();
        $IN_REDIRECT = eval($section_text['REDIRECTTEST']);
        $IN_REDIRECT['via'] = "via [{$shortname}]\n\t";
        $IN_REDIRECT['dir'] = realpath(dirname($file));
        $IN_REDIRECT['prefix'] = trim($section_text['TEST']);
        if (count($IN_REDIRECT['TESTS']) == 1) {
            if (is_array($org_file)) {
                $test_files[] = $org_file[1];
            } else {
                $GLOBALS['test_files'] = $test_files;
                find_files($IN_REDIRECT['TESTS']);
                foreach ($GLOBALS['test_files'] as $f) {
                    $test_files[] = array($f, $file);
                }
            }
            $test_cnt += @count($test_files) - 1;
            $test_idx--;
            show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file);
            // set up environment
            $redirenv = array_merge($environment, $IN_REDIRECT['ENV']);
            $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR;
            usort($test_files, "test_sort");
            run_all_tests($test_files, $redirenv, $tested);
            show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file);
            // a redirected test never fails
            $IN_REDIRECT = false;
            return 'REDIR';
        } else {
            $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory.";
            show_result("BORK", $bork_info, '', $temp_filenames);
            $PHP_FAILED_TESTS['BORKED'][] = array('name' => $file, 'test_name' => '', 'output' => '', 'diff' => '', 'info' => "{$bork_info} [{$file}]");
        }
    }
    if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) {
        if (is_array($org_file)) {
            $file = $org_file[0];
        }
        $bork_info = "Redirected test did not contain redirection info";
        show_result("BORK", $bork_info, '', $temp_filenames);
        $PHP_FAILED_TESTS['BORKED'][] = array('name' => $file, 'test_name' => '', 'output' => '', 'diff' => '', 'info' => "{$bork_info} [{$file}]");
        return 'BORKED';
    }
    // We've satisfied the preconditions - run the test!
    show_file_block('php', $section_text['FILE'], 'TEST');
    save_text($test_file, $section_text['FILE'], $temp_file);
    if (array_key_exists('GET', $section_text)) {
        $query_string = trim($section_text['GET']);
    } else {
        $query_string = '';
    }
    $env['REDIRECT_STATUS'] = '1';
    $env['QUERY_STRING'] = $query_string;
    $env['PATH_TRANSLATED'] = $test_file;
    $env['SCRIPT_FILENAME'] = $test_file;
    if (array_key_exists('COOKIE', $section_text)) {
        $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
    } else {
        $env['HTTP_COOKIE'] = '';
    }
    $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : '';
    if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
        $post = trim($section_text['POST_RAW']);
        $raw_lines = explode("\n", $post);
        $request = '';
        $started = false;
        foreach ($raw_lines as $line) {
            if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
                $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
                continue;
            }
            if ($started) {
                $request .= "\n";
            }
            $started = true;
            $request .= $line;
        }
        $env['CONTENT_LENGTH'] = strlen($request);
        $env['REQUEST_METHOD'] = 'POST';
        if (empty($request)) {
            return 'BORKED';
        }
        save_text($tmp_post, $request);
        $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\" 2>&1 < {$tmp_post}";
    } else {
        if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
            $post = trim($section_text['POST']);
            if (array_key_exists('GZIP_POST', $section_text) && function_exists('gzencode')) {
                $post = gzencode($post, 9, FORCE_GZIP);
                $env['HTTP_CONTENT_ENCODING'] = 'gzip';
            } else {
                if (array_key_exists('DEFLATE_POST', $section_text) && function_exists('gzcompress')) {
                    $post = gzcompress($post, 9);
                    $env['HTTP_CONTENT_ENCODING'] = 'deflate';
                }
            }
            save_text($tmp_post, $post);
            $content_length = strlen($post);
            $env['REQUEST_METHOD'] = 'POST';
            $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
            $env['CONTENT_LENGTH'] = $content_length;
            $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\" 2>&1 < {$tmp_post}";
        } else {
            $env['REQUEST_METHOD'] = 'GET';
            $env['CONTENT_TYPE'] = '';
            $env['CONTENT_LENGTH'] = '';
            $cmd = "{$php} {$pass_options} {$ini_settings} -f \"{$test_file}\" {$args} 2>&1";
        }
    }
    if ($leak_check) {
        $env['USE_ZEND_ALLOC'] = '0';
        if ($valgrind_version >= 330) {
            /* valgrind 3.3.0+ doesn't have --log-file-exactly option */
            $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file={$memcheck_filename} {$cmd}";
        } else {
            $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly={$memcheck_filename} {$cmd}";
        }
    } else {
        $env['USE_ZEND_ALLOC'] = '1';
    }
    if ($DETAILED) {
        echo "\nCONTENT_LENGTH  = " . $env['CONTENT_LENGTH'] . "\nCONTENT_TYPE    = " . $env['CONTENT_TYPE'] . "\nPATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . "\nQUERY_STRING    = " . $env['QUERY_STRING'] . "\nREDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . "\nREQUEST_METHOD  = " . $env['REQUEST_METHOD'] . "\nSCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . "\nHTTP_COOKIE     = " . $env['HTTP_COOKIE'] . "\nCOMMAND {$cmd}\n";
    }
    $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null);
    if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) {
        if (trim($section_text['CLEAN'])) {
            show_file_block('clean', $section_text['CLEAN']);
            save_text($test_clean, trim($section_text['CLEAN']), $temp_clean);
            if (!$no_clean) {
                $clean_params = array();
                settings2array($ini_overwrites, $clean_params);
                settings2params($clean_params);
                $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
                system_with_timeout("{$extra} {$php} {$pass_options} -q {$clean_params} {$test_clean}", $env);
            }
            if (!$cfg['keep']['clean']) {
                @unlink($test_clean);
            }
        }
    }
    @unlink($tmp_post);
    $leaked = false;
    $passed = false;
    if ($leak_check) {
        // leak check
        $leaked = filesize($memcheck_filename) > 0;
        if (!$leaked) {
            @unlink($memcheck_filename);
        }
    }
    // Does the output match what is expected?
    $output = preg_replace("/\r\n/", "\n", trim($out));
    /* when using CGI, strip the headers from the output */
    $headers = "";
    if (isset($old_php) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
        $output = trim($match[2]);
        $rh = preg_split("/[\n\r]+/", $match[1]);
        $headers = array();
        foreach ($rh as $line) {
            if (strpos($line, ':') !== false) {
                $line = explode(':', $line, 2);
                $headers[trim($line[0])] = trim($line[1]);
            }
        }
    }
    $failed_headers = false;
    if (isset($section_text['EXPECTHEADERS'])) {
        $want = array();
        $wanted_headers = array();
        $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']);
        foreach ($lines as $line) {
            if (strpos($line, ':') !== false) {
                $line = explode(':', $line, 2);
                $want[trim($line[0])] = trim($line[1]);
                $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]);
            }
        }
        $org_headers = $headers;
        $headers = array();
        $output_headers = array();
        foreach ($want as $k => $v) {
            if (isset($org_headers[$k])) {
                $headers = $org_headers[$k];
                $output_headers[] = $k . ': ' . $org_headers[$k];
            }
            if (!isset($org_headers[$k]) || $org_headers[$k] != $v) {
                $failed_headers = true;
            }
        }
        ksort($wanted_headers);
        $wanted_headers = join("\n", $wanted_headers);
        ksort($output_headers);
        $output_headers = join("\n", $output_headers);
    }
    show_file_block('out', $output);
    if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
        if (isset($section_text['EXPECTF'])) {
            $wanted = trim($section_text['EXPECTF']);
        } else {
            $wanted = trim($section_text['EXPECTREGEX']);
        }
        show_file_block('exp', $wanted);
        $wanted_re = preg_replace('/\\r\\n/', "\n", $wanted);
        if (isset($section_text['EXPECTF'])) {
            $wanted_re = preg_quote($wanted_re, '/');
            $wanted_re = str_replace(array('%unicode_string_optional%'), version_compare(PHP_VERSION, '6.0.0-dev') == -1 ? 'string' : 'Unicode string', $wanted_re);
            $wanted_re = str_replace(array('%unicode\\|string%', '%string\\|unicode%'), version_compare(PHP_VERSION, '6.0.0-dev') == -1 ? 'string' : 'unicode', $wanted_re);
            $wanted_re = str_replace(array('%u\\|b%', '%b\\|u%'), version_compare(PHP_VERSION, '6.0.0-dev') == -1 ? '' : 'u', $wanted_re);
            // Stick to basics
            $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re);
            $wanted_re = str_replace('%s', '[^\\r\\n]+', $wanted_re);
            $wanted_re = str_replace('%a', '.+', $wanted_re);
            $wanted_re = str_replace('%w', '\\s*', $wanted_re);
            $wanted_re = str_replace('%i', '[+-]?\\d+', $wanted_re);
            $wanted_re = str_replace('%d', '\\d+', $wanted_re);
            $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re);
            $wanted_re = str_replace('%f', '[+-]?\\.?\\d+\\.?\\d*(?:[Ee][+-]?\\d+)?', $wanted_re);
            $wanted_re = str_replace('%c', '.', $wanted_re);
            // %f allows two points "-.0.0" but that is the best *simple* expression
        }
        /* DEBUG YOUR REGEX HERE
        		var_dump($wanted_re);
        		print(str_repeat('=', 80) . "\n");
        		var_dump($output);
        */
        if (preg_match((string) "/^{$wanted_re}\$/s", $output)) {
            $passed = true;
            if (!$cfg['keep']['php']) {
                @unlink($test_file);
            }
            if (isset($old_php)) {
                $php = $old_php;
            }
            if (!$leaked && !$failed_headers) {
                show_result("PASS", $tested, $tested_file, '', $temp_filenames);
                return 'PASSED';
            }
        }
    } else {
        $wanted = trim($section_text['EXPECT']);
        $wanted = preg_replace('/\\r\\n/', "\n", $wanted);
        show_file_block('exp', $wanted);
        // compare and leave on success
        if (!strcmp($output, $wanted)) {
            $passed = true;
            if (!$cfg['keep']['php']) {
                @unlink($test_file);
            }
            if (isset($old_php)) {
                $php = $old_php;
            }
            if (!$leaked && !$failed_headers) {
                show_result("PASS", $tested, $tested_file, '', $temp_filenames);
                return 'PASSED';
            }
        }
        $wanted_re = null;
    }
    // Test failed so we need to report details.
    if ($failed_headers) {
        $passed = false;
        $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted;
        $output = $output_headers . "\n--HEADERS--\n" . $output;
        if (isset($wanted_re)) {
            $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re;
        }
    }
    if ($leaked) {
        $restype[] = 'LEAK';
    }
    if ($warn) {
        $restype[] = 'WARN';
    }
    if (!$passed) {
        if (isset($section_text['XFAIL'])) {
            $restype[] = 'XFAIL';
        } else {
            $restype[] = 'FAIL';
        }
    }
    if (!$passed) {
        // write .exp
        if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, (string) $wanted, FILE_BINARY) === false) {
            error("Cannot create expected test output - {$exp_filename}");
        }
        // write .out
        if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, (string) $output, FILE_BINARY) === false) {
            error("Cannot create test output - {$output_filename}");
        }
        // write .diff
        $diff = generate_diff($wanted, $wanted_re, $output);
        show_file_block('diff', $diff);
        if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, (string) $diff, FILE_BINARY) === false) {
            error("Cannot create test diff - {$diff_filename}");
        }
        // write .log
        if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, "\n---- EXPECTED OUTPUT\n{$wanted}\n---- ACTUAL OUTPUT\n{$output}\n---- FAILED\n", FILE_BINARY) === false) {
            error("Cannot create test log - {$log_filename}");
            error_report($file, $log_filename, $tested);
        }
    }
    show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames);
    foreach ($restype as $type) {
        $PHP_FAILED_TESTS[$type . 'ED'][] = array('name' => $file, 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [{$tested_file}]", 'output' => $output_filename, 'diff' => $diff_filename, 'info' => $info);
    }
    if (isset($old_php)) {
        $php = $old_php;
    }
    return $restype[0] . 'ED';
}
function run_test($php, $file, $env)
{
    global $log_format, $info_params, $ini_overwrites, $cwd, $PHP_FAILED_TESTS;
    global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx;
    global $leak_check, $temp_source, $temp_target, $cfg, $environment;
    global $no_clean;
    $temp_filenames = null;
    $org_file = $file;
    if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) {
        $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
    }
    if (is_array($file)) {
        $file = $file[0];
    }
    if ($DETAILED) {
        echo "\n=================\nTEST {$file}\n";
    }
    // Load the sections of the test file.
    $section_text = array('TEST' => '', 'SKIPIF' => '', 'GET' => '', 'POST_RAW' => '', 'POST' => '', 'UPLOAD' => '', 'ARGS' => '');
    $fp = @fopen($file, "rt") or error("Cannot open test file: {$file}");
    $borked = false;
    $bork_info = '';
    if (!feof($fp)) {
        $line = fgets($fp);
    } else {
        $bork_info = "empty test [{$file}]";
        $borked = true;
    }
    if (!ereg('^--TEST--', $line, $r)) {
        $bork_info = "tests must start with --TEST-- [{$file}]";
        $borked = true;
    }
    $section = 'TEST';
    $secfile = false;
    $secdone = false;
    while (!feof($fp)) {
        $line = fgets($fp);
        // Match the beginning of a section.
        if (preg_match('/^--([A-Z_]+)--/', $line, $r)) {
            $section = $r[1];
            $section_text[$section] = '';
            $secfile = $section == 'FILE' || $section == 'FILEEOF';
            $secdone = false;
            continue;
        }
        // Add to the section text.
        if (!$secdone) {
            $section_text[$section] .= $line;
        }
        // End of actual test?
        if ($secfile && preg_match('/^===DONE===/', $line, $r)) {
            $secdone = true;
        }
    }
    // the redirect section allows a set of tests to be reused outside of
    // a given test dir
    if (@count($section_text['REDIRECTTEST']) == 1) {
        if ($IN_REDIRECT) {
            $borked = true;
            $bork_info = "Can't redirect a test from within a redirected test";
        } else {
            $borked = false;
        }
    } else {
        if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) != 1) {
            $bork_info = "missing section --FILE--";
            $borked = true;
        }
        if (@count($section_text['FILEEOF']) == 1) {
            $section_text['FILE'] = preg_replace("/[\r\n]+\$/", '', $section_text['FILEEOF']);
            unset($section_text['FILEEOF']);
        }
        if (@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX']) != 1) {
            $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
            $borked = true;
        }
    }
    fclose($fp);
    $shortname = str_replace($cwd . '/', '', $file);
    $tested_file = $shortname;
    if ($borked) {
        show_result("BORK", $bork_info, $tested_file);
        $PHP_FAILED_TESTS['BORKED'][] = array('name' => $file, 'test_name' => '', 'output' => '', 'diff' => '', 'info' => "{$bork_info} [{$file}]");
        return 'BORKED';
    }
    $tested = trim($section_text['TEST']);
    /* For GET/POST tests, check if cgi sapi is available and if it is, use it. */
    if (!empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['POST_RAW'])) {
        if (isset($php_cgi)) {
            $old_php = $php;
            $php = $php_cgi . ' -C ';
        } elseif (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) {
            $old_php = $php;
            $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C ';
        } elseif (file_exists("./sapi/cgi/php")) {
            $old_php = $php;
            $php = realpath("./sapi/cgi/php") . ' -C ';
        } else {
            show_result("SKIP", $tested, $tested_file, "reason: CGI not available");
            return 'SKIPPED';
        }
    }
    show_test($test_idx, $shortname);
    if (is_array($IN_REDIRECT)) {
        $temp_dir = $test_dir = $IN_REDIRECT['dir'];
    } else {
        $temp_dir = $test_dir = realpath(dirname($file));
    }
    if ($temp_source && $temp_target) {
        $temp_dir = str_replace($temp_source, $temp_target, $temp_dir);
    }
    $main_file_name = basename($file, 'phpt');
    $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff';
    $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log';
    $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp';
    $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out';
    $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem';
    $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
    $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
    $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
    $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
    $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
    $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
    $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.');
    $tmp_relative_file = str_replace(dirname(__FILE__) . DIRECTORY_SEPARATOR, '', $test_file) . 't';
    if ($temp_source && $temp_target) {
        $temp_skipif .= 's';
        $temp_file .= 's';
        $temp_clean .= 's';
        $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps';
        if (!is_dir(dirname($copy_file))) {
            @mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file));
        }
        if (isset($section_text['FILE'])) {
            save_text($copy_file, $section_text['FILE']);
        }
        $temp_filenames = array('file' => $copy_file, 'diff' => $diff_filename, 'log' => $log_filename, 'exp' => $exp_filename, 'out' => $output_filename, 'mem' => $memcheck_filename, 'php' => $temp_file, 'skip' => $temp_skipif, 'clean' => $temp_clean);
    }
    if (is_array($IN_REDIRECT)) {
        $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']);
        $tested_file = $tmp_relative_file;
        $section_text['FILE'] = "# original source file: {$shortname}\n" . $section_text['FILE'];
    }
    // unlink old test results
    @unlink($diff_filename);
    @unlink($log_filename);
    @unlink($exp_filename);
    @unlink($output_filename);
    @unlink($memcheck_filename);
    @unlink($temp_file);
    @unlink($test_file);
    @unlink($temp_skipif);
    @unlink($test_skipif);
    @unlink($tmp_post);
    @unlink($temp_clean);
    @unlink($test_clean);
    // Reset environment from any previous test.
    $env['REDIRECT_STATUS'] = '';
    $env['QUERY_STRING'] = '';
    $env['PATH_TRANSLATED'] = '';
    $env['SCRIPT_FILENAME'] = '';
    $env['REQUEST_METHOD'] = '';
    $env['CONTENT_TYPE'] = '';
    $env['CONTENT_LENGTH'] = '';
    if (!empty($section_text['ENV'])) {
        foreach (explode("\n", $section_text['ENV']) as $e) {
            $e = explode('=', trim($e));
            if (count($e) == 2) {
                $env[$e[0]] = $e[1];
            }
        }
    }
    // Default ini settings
    $ini_settings = array();
    // additional ini overwrites
    //$ini_overwrites[] = 'setting=value';
    settings2array($ini_overwrites, $ini_settings);
    // Any special ini settings
    // these may overwrite the test defaults...
    if (array_key_exists('INI', $section_text)) {
        if (strpos($section_text['INI'], '{PWD}') !== false) {
            $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
        }
        settings2array(preg_split("/[\n\r]+/", $section_text['INI']), $ini_settings);
    }
    settings2params($ini_settings);
    // Check if test should be skipped.
    $info = '';
    $warn = false;
    if (array_key_exists('SKIPIF', $section_text)) {
        if (trim($section_text['SKIPIF'])) {
            if ($cfg['show']['skip']) {
                echo "\n========SKIP========\n";
                echo $section_text['SKIPIF'];
                echo "========DONE========\n";
            }
            save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif);
            $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
            $output = system_with_timeout("{$extra} {$php} -q {$ini_settings} {$test_skipif}", $env);
            if (!$cfg['keep']['skip']) {
                @unlink($test_skipif);
            }
            if (!strncasecmp('skip', trim($output), 4)) {
                $reason = eregi("^skip[[:space:]]*(.+)\$", trim($output)) ? eregi_replace("^skip[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE;
                if ($reason) {
                    show_result("SKIP", $tested, $tested_file, "reason: {$reason}", $temp_filenames);
                } else {
                    show_result("SKIP", $tested, $tested_file, '', $temp_filenames);
                }
                if (isset($old_php)) {
                    $php = $old_php;
                }
                if (!$cfg['keep']['skip']) {
                    @unlink($test_skipif);
                }
                return 'SKIPPED';
            }
            if (!strncasecmp('info', trim($output), 4)) {
                $reason = ereg("^info[[:space:]]*(.+)\$", trim($output)) ? ereg_replace("^info[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE;
                if ($reason) {
                    $info = " (info: {$reason})";
                }
            }
            if (!strncasecmp('warn', trim($output), 4)) {
                $reason = ereg("^warn[[:space:]]*(.+)\$", trim($output)) ? ereg_replace("^warn[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE;
                if ($reason) {
                    $warn = true;
                    /* only if there is a reason */
                    $info = " (warn: {$reason})";
                }
            }
        }
    }
    if (@count($section_text['REDIRECTTEST']) == 1) {
        $test_files = array();
        $IN_REDIRECT = eval($section_text['REDIRECTTEST']);
        $IN_REDIRECT['via'] = "via [{$shortname}]\n\t";
        $IN_REDIRECT['dir'] = realpath(dirname($file));
        $IN_REDIRECT['prefix'] = trim($section_text['TEST']);
        if (@count($IN_REDIRECT['TESTS']) == 1) {
            if (is_array($org_file)) {
                $test_files[] = $org_file[1];
            } else {
                $GLOBALS['test_files'] = $test_files;
                find_files($IN_REDIRECT['TESTS']);
                foreach ($GLOBALS['test_files'] as $f) {
                    $test_files[] = array($f, $file);
                }
            }
            $test_cnt += count($test_files) - 1;
            $test_idx--;
            show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file);
            // set up environment
            $redirenv = array_merge($environment, $IN_REDIRECT['ENV']);
            $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR;
            usort($test_files, "test_sort");
            run_all_tests($test_files, $redirenv, $tested);
            show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file);
            // a redirected test never fails
            $IN_REDIRECT = false;
            return 'REDIR';
        }
    }
    if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) {
        if (is_array($org_file)) {
            $file = $org_file[0];
        }
        $bork_info = "Redirected test did not contain redirection info";
        show_result("BORK", $bork_info, '', $temp_filenames);
        $PHP_FAILED_TESTS['BORKED'][] = array('name' => $file, 'test_name' => '', 'output' => '', 'diff' => '', 'info' => "{$bork_info} [{$file}]");
        //$test_cnt -= 1;  // Only if is_array($org_file) ?
        //$test_idx--;
        return 'BORKED';
    }
    // We've satisfied the preconditions - run the test!
    if ($cfg['show']['php']) {
        echo "\n========TEST========\n";
        echo $section_text['FILE'];
        echo "========DONE========\n";
    }
    save_text($test_file, $section_text['FILE'], $temp_file);
    if (array_key_exists('GET', $section_text)) {
        $query_string = trim($section_text['GET']);
    } else {
        $query_string = '';
    }
    $env['REDIRECT_STATUS'] = '1';
    $env['QUERY_STRING'] = $query_string;
    $env['PATH_TRANSLATED'] = $test_file;
    $env['SCRIPT_FILENAME'] = $test_file;
    $args = $section_text['ARGS'] ? ' -- ' . $section_text['ARGS'] : '';
    if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
        $post = trim($section_text['POST_RAW']);
        $raw_lines = explode("\n", $post);
        $request = '';
        foreach ($raw_lines as $line) {
            if (empty($env['CONTENT_TYPE']) && eregi('^(Content-Type:)(.*)', $line, $res)) {
                $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[2]));
                continue;
            }
            $request .= $line . "\n";
        }
        $env['CONTENT_LENGTH'] = strlen($request);
        $env['REQUEST_METHOD'] = 'POST';
        if (empty($request)) {
            return 'BORKED';
        }
        save_text($tmp_post, $request);
        $cmd = "{$php}{$pass_options}{$ini_settings} -f \"{$test_file}\" 2>&1 < {$tmp_post}";
    } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
        $post = trim($section_text['POST']);
        save_text($tmp_post, $post);
        $content_length = strlen($post);
        $env['REQUEST_METHOD'] = 'POST';
        $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
        $env['CONTENT_LENGTH'] = $content_length;
        $cmd = "{$php}{$pass_options}{$ini_settings} -f \"{$test_file}\" 2>&1 < {$tmp_post}";
    } else {
        $env['REQUEST_METHOD'] = 'GET';
        $env['CONTENT_TYPE'] = '';
        $env['CONTENT_LENGTH'] = '';
        $cmd = "{$php}{$pass_options}{$ini_settings} -f \"{$test_file}\" {$args} 2>&1";
    }
    if ($leak_check) {
        $cmd = "valgrind -q --tool=memcheck --log-file-exactly={$memcheck_filename} {$cmd}";
    }
    if ($DETAILED) {
        echo "\nCONTENT_LENGTH  = " . $env['CONTENT_LENGTH'] . "\nCONTENT_TYPE    = " . $env['CONTENT_TYPE'] . "\nPATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . "\nQUERY_STRING    = " . $env['QUERY_STRING'] . "\nREDIRECT_STATUS = " . $env['REDIRECT_STATUS'] . "\nREQUEST_METHOD  = " . $env['REQUEST_METHOD'] . "\nSCRIPT_FILENAME = " . $env['SCRIPT_FILENAME'] . "\nCOMMAND {$cmd}\n";
    }
    $out = system_with_timeout($cmd, $env);
    if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) {
        if (trim($section_text['CLEAN'])) {
            if ($cfg['show']['clean']) {
                echo "\n========CLEAN=======\n";
                echo $section_text['CLEAN'];
                echo "========DONE========\n";
            }
            save_text($test_clean, trim($section_text['CLEAN']), $temp_clean);
            if (!$no_clean) {
                $clean_params = array();
                settings2array($ini_overwrites, $clean_params);
                settings2params($clean_params);
                $extra = substr(PHP_OS, 0, 3) !== "WIN" ? "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
                system_with_timeout("{$extra} {$php} -q {$clean_params} {$test_clean}", $env);
            }
            if (!$cfg['keep']['clean']) {
                @unlink($test_clean);
            }
        }
    }
    @unlink($tmp_post);
    $leaked = false;
    $passed = false;
    if ($leak_check) {
        // leak check
        $leaked = @filesize($memcheck_filename) > 0;
        if (!$leaked) {
            @unlink($memcheck_filename);
        }
    }
    // Does the output match what is expected?
    $output = str_replace("\r\n", "\n", trim($out));
    /* when using CGI, strip the headers from the output */
    if (isset($old_php) && ($pos = strpos($output, "\n\n")) !== FALSE) {
        $output = substr($output, $pos + 2);
    }
    if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
        if (isset($section_text['EXPECTF'])) {
            $wanted = trim($section_text['EXPECTF']);
        } else {
            $wanted = trim($section_text['EXPECTREGEX']);
        }
        $wanted_re = preg_replace('/\\r\\n/', "\n", $wanted);
        if (isset($section_text['EXPECTF'])) {
            $wanted_re = preg_quote($wanted_re, '/');
            // Stick to basics
            $wanted_re = str_replace("%e", '\\' . DIRECTORY_SEPARATOR, $wanted_re);
            $wanted_re = str_replace("%s", ".+?", $wanted_re);
            //not greedy
            $wanted_re = str_replace("%w", "\\s*", $wanted_re);
            $wanted_re = str_replace("%i", "[+\\-]?[0-9]+", $wanted_re);
            $wanted_re = str_replace("%d", "[0-9]+", $wanted_re);
            $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re);
            $wanted_re = str_replace("%f", "[+\\-]?\\.?[0-9]+\\.?[0-9]*(E-?[0-9]+)?", $wanted_re);
            $wanted_re = str_replace("%c", ".", $wanted_re);
            // %f allows two points "-.0.0" but that is the best *simple* expression
        }
        /* DEBUG YOUR REGEX HERE
        		var_dump($wanted_re);
        		print(str_repeat('=', 80) . "\n");
        		var_dump($output);
        */
        if (preg_match("/^{$wanted_re}\$/s", $output)) {
            $passed = true;
            if (!$cfg['keep']['php']) {
                @unlink($test_file);
            }
            if (isset($old_php)) {
                $php = $old_php;
            }
            if (!$leaked) {
                show_result("PASS", $tested, $tested_file, '', $temp_filenames);
                return 'PASSED';
            }
        }
    } else {
        $wanted = trim($section_text['EXPECT']);
        $wanted = preg_replace('/\\r\\n/', "\n", $wanted);
        // compare and leave on success
        if (!strcmp($output, $wanted)) {
            $passed = true;
            if (!$cfg['keep']['php']) {
                @unlink($test_file);
            }
            if (isset($old_php)) {
                $php = $old_php;
            }
            if (!$leaked) {
                show_result("PASS", $tested, $tested_file, '', $temp_filenames);
                return 'PASSED';
            }
        }
        $wanted_re = NULL;
    }
    // Test failed so we need to report details.
    if ($leaked) {
        $restype = 'LEAK';
    } else {
        if ($warn) {
            $restype = 'WARN';
        } else {
            $restype = 'FAIL';
        }
    }
    if (!$passed) {
        // write .exp
        if (strpos($log_format, 'E') !== FALSE && file_put_contents($exp_filename, $wanted) === FALSE) {
            error("Cannot create expected test output - {$exp_filename}");
        }
        // write .out
        if (strpos($log_format, 'O') !== FALSE && file_put_contents($output_filename, $output) === FALSE) {
            error("Cannot create test output - {$output_filename}");
        }
        // write .diff
        if (strpos($log_format, 'D') !== FALSE && file_put_contents($diff_filename, generate_diff($wanted, $wanted_re, $output)) === FALSE) {
            error("Cannot create test diff - {$diff_filename}");
        }
        // write .log
        if (strpos($log_format, 'L') !== FALSE && file_put_contents($log_filename, "\n---- EXPECTED OUTPUT\n{$wanted}\n---- ACTUAL OUTPUT\n{$output}\n---- FAILED\n") === FALSE) {
            error("Cannot create test log - {$log_filename}");
            error_report($file, $log_filename, $tested);
        }
    }
    show_result($restype, $tested, $tested_file, $info, $temp_filenames);
    $PHP_FAILED_TESTS[$restype . 'ED'][] = array('name' => $file, 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [{$tested_file}]", 'output' => $output_filename, 'diff' => $diff_filename, 'info' => $info);
    if (isset($old_php)) {
        $php = $old_php;
    }
    return $restype . 'ED';
}