]> granicus.if.org Git - php/commitdiff
Updated to run cleanly on Win32, and perform a more controlled test.
authorPreston L. Bannister <pbannister@php.net>
Thu, 16 May 2002 21:48:28 +0000 (21:48 +0000)
committerPreston L. Bannister <pbannister@php.net>
Thu, 16 May 2002 21:48:28 +0000 (21:48 +0000)
run-tests.php

index d5bf760f2109196f4142ac80792adc014cdd523c..d0a066a5a2fa435b0bccc5f220abb7f0658662a5 100755 (executable)
    | obtain it through the world-wide-web, please send a note to          |
    | license@php.net so we can mail you a copy immediately.               |
    +----------------------------------------------------------------------+
-   | Author: Stig Bakken <ssb@fast.no>                                    |
+   | (based on version by: Stig Bakken <ssb@fast.no>)                     |
    | (based on the PHP 3 test framework by Rasmus Lerdorf)                |
    +----------------------------------------------------------------------+
  */
 
+/*
+    History
+    -------
+
+    2002-05-07  Preston L. Bannister <preston.bannister@cox.net>
+
+    Rewrote and updated to run on Win32.  
+
+    Require exact specification of PHP executable to test (no guessing!).
+
+    Require a specific tests/php.ini (rather than whatever is lying around),
+    and test that this is indeed what we are using.
+
+    Die if any internal errors encountered in test script.
+
+    Regularized output for simpler post-processing of output.
+
+    Optionally output error lines indicating the failing test source and log
+    for direct jump with MSVC or Emacs.
+
+    Run basic (non-extension) tests first.  Treat PEAR as extension.
+
+    Tested on Windows 2000 with the Cygnus Win32 toolkit installed.
+*/
+
 /*
  * TODO:
- * - look for test-specific php.ini files
- * - implement module skipping for PEAR
  * - do not test PEAR components if base class and/or component class cannot be instanciated
  */
 
+set_time_limit(0);
+ob_implicit_flush();
+
 if (ini_get('safe_mode')) {
-       echo <<<SAFE_MODE_WARNING
+    echo <<<SAFE_MODE_WARNING
 
 +-----------------------------------------------------------+
 |                       ! WARNING !                         |
@@ -40,595 +66,417 @@ if (ini_get('safe_mode')) {
 SAFE_MODE_WARNING;
 }
 
+// Don't ever guess at the PHP executable location.
+// Require the explicit specification.
+// Otherwise we could end up testing the wrong file!
 
-set_time_limit(0);
+$php = $_ENV['TEST_PHP_EXECUTABLE'];
 
-ob_implicit_flush();
+isset($php)
+    or die("FAIL environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!\n");
 
-define('TEST_PASSED', 0);
-define('TEST_FAILED', -1);
-define('TEST_SKIPPED', -2);
-define('TEST_INTERNAL_ERROR', -3);
+@is_executable($php)
+    or die("FAIL invalid PHP executable specified by TEST_PHP_EXECUTABLE  = " . $php . "\n");
 
-define('EXT_DIR_NAME','/php4/ext/');
-define('EXT_DIR_NAME_LEN',strlen(EXT_DIR_NAME));
+// Check whether a detailed log is wanted.
 
-initialize();
-/*
-$opts = parse_options(&$argc, &$argv);
-if ($opts['help']) {
-    usage();
-    exit;
-}
-*/
+define('DETAILED',0 + $_ENV['TEST_PHP_DETAILED']);
 
-if(!isset($_SERVER['argc'])) {
-       echo "\nWARNING: register_argc_argv seems to be set 'off' in php.ini\n\n";
-}      
+// Write INI file to be used in tests.
 
-@do_testing($_SERVER['argc'], $_SERVER['argv']);
+$include_path = getcwd();
 
-exit;
+$test_ini = realpath(dirname($php) . "/php.ini");
+save_text($test_ini,"[PHP]\ninclude_path = \"$include_path\"\n");
 
-/*****************************************************************************/
+// Write test context information.
 
-function usage()
-{
-    dowriteln("Usage: run-tests.php [-d] [-h] [dir|file...]");
-}
+echo "
+=====================================================================
+TIME " . date('Y-m-d H:i:s') . " - start of test run
+CWD         : " . getcwd() . "
+PHP         : $php
+PHP_SAPI    : " . PHP_SAPI . "
+PHP_VERSION : " . PHP_VERSION . "
+PHP_OS      : " . PHP_OS . "
+INI actual  : " . get_cfg_var('cfg_file_path') . "
+INI wanted  : " . realpath('tests/php.ini') . "
+INI tests   : $test_ini
+=====================================================================
 
-/*
- * Please use dowrite() and dowriteln() for all screen output.
- * This makes it easier to convert to HTML output later.
- */
+";
 
-function dowrite($str)
-{
-    global $term_bold, $term_norm;
-    $str = str_replace("%b", $term_bold, $str);
-    $str = str_replace("%B", $term_norm, $str);
-    print $str;
-}
+// Make sure we are using the proper php.ini.
 
-function dowriteln($str)
-{
-    dowrite("$str\n");
-}
+$php_ini = realpath("tests/php.ini");
+realpath(get_cfg_var('cfg_file_path')) == $php_ini
+    or die("FAIL test/php.ini was not used!\n");
 
-function create_compiled_in_modules_list()  {
-    global $compiled_in_modules;
-    $compiled_in_modules = @get_loaded_extensions();
-}
+// Determine the tests to be run.
 
-function extract_module_name_from_path($path)   {
-    if ($pos1=strpos($path,EXT_DIR_NAME)) {
-               $pos3=strpos($path,'/',$pos1+EXT_DIR_NAME_LEN);
-               return substr($path,$pos2=$pos1+EXT_DIR_NAME_LEN,$pos3-$pos2);
-    }
-}
-
-
-function create_found_tests_4_modules_list() {
-       global $modules_2_test,$testdirs;
-
-       foreach ($testdirs AS $path) {
-               if ($mod_name=extract_module_name_from_path($path))
-                       $modules_2_test[$mod_name]=TRUE;
-       }
-}
-
-function create_modules_2_test_list() {
-    global $compiled_in_modules,$modules_2_test,$modules_available;
-    foreach ($compiled_in_modules AS $value)
-       if (isset($modules_2_test[$value])) $modules_available[]=$value;
-}
+$test_to_run = array();
+$test_files = array();
+$test_results = array();
 
+if (isset($_SERVER['argc'])) {
 
+    // If parameters given assume they represent selected tests to run.
 
-function in_path($program, $windows_p)
-{
-    global $HTTP_ENV_VARS;
-    if ($windows_p) {
-        $delim = ";";
-        $ext = ".exe";
-    } else {
-        $delim = ":";
-        $ext = "";
+    $argc = $_SERVER['argc'];
+    $argv = $_SERVER['argv'];
+    for ($i = 1; $i < $argc; $i++) {
+        $testfile = realpath($argv[$i]);
+        $test_to_run[$testfile] = 1;
     }
-    $slash = DIRECTORY_SEPARATOR;
-    $path_components = explode($delim, $HTTP_ENV_VARS['PATH']);
-    if ($windows_p) {
-               $cwd = getcwd() . DIRECTORY_SEPARATOR;
-               array_unshift($path_components, "{$cwd}Release_TS_Inline", "{$cwd}Release_TS");
-    }
-    foreach ($path_components as $path) {
-        $test = "{$path}{$slash}php{$ext}";
-        if (@is_executable($test)) {
-            return $test;
-        }
-    }
-    return false;
+    
 }
 
+// Compile a list of all test files (*.phpt).
 
-function initialize()
 {
-    global $term, $windows_p, $php, $skip, $testdirs, $tmpfile,
-       $skipped, $failed, $passed, $total, $term_bold, $term_norm,
-       $tests_in_dir;
-
-    // XXX Should support HTML output as well.
-    $php = "";
-    if((substr(PHP_OS, 0, 3) == "WIN")) {
-        $ext = ".exe";
-        $windows_p = true;
-        $term = getenv("COMSPEC");
-    } else {
-        $ext = "";
-        $term = getenv("TERM");
-        if (ereg('^(xterm|vt220)', $term)) {
-            $term_bold = sprintf("%c%c%c%c", 27, 91, 49, 109);
-            $term_norm = sprintf("%c%c%c", 27, 91, 109);
-        } elseif (ereg('^vt100', $term)) {
-            $term_bold = sprintf("%c%c%c%c", 27, 91, 49, 109);
-            $term_norm = sprintf("%c%c%c", 27, 91, 109);
-        } else {
-            $term_bold = $term_norm = "";
+    $directories = array();
+    $directories[] = getcwd();
+    for ($n = 0; $n < count($directories); $n++) {
+        $path = $directories[$n];
+        $module = '';
+        if (ereg('/ext/([^/]+)/',"$path/",$r)) {
+            $module = $r[1];
+        } else if (ereg('/pear/',"$path/")) {
+            $module = 'PEAR';
         }
-    }
-
-/*  We need to check CGI SAPI first since some tests must be skipped when
-    CLI SAPI is used. CLI SAPI is built always while CGI SAPI is not.
-    - yohgaki@php.net */
-
-       if (isset($_ENV["TOP_BUILDDIR"]) && @is_executable($_ENV["TOP_BUILDDIR"]."/php{$ext}")) {
-        $php = $_ENV["TOP_BUILDDIR"]."/php{$ext}";
-    } elseif (@is_executable("./php{$ext}")) {
-        $php = getcwd() . "/php{$ext}";
-       } elseif (isset($_ENV["TOP_BUILDDIR"]) && @is_executable($_ENV["TOP_BUILDDIR"]."/sapi/cli/php{$ext}")) {
-        $php = $_ENV["TOP_BUILDDIR"]."/sapi/cli/php{$ext}";
-    } elseif (@is_executable("./sapi/cli/php{$ext}")) {
-        $php = getcwd() . "/sapi/cli/php{$ext}";
-    } elseif (@is_executable(PHP_BINDIR . "/php{$ext}")) {
-        $php = PHP_BINDIR . "/php{$ext}";
-    }
-// Test result can be bogus, if we use php binary in path. - yohgaki@php.net
-//     if (empty($php)) {
-//         $php = in_path("php", $windows_p);
-//     }
-    if (empty($php)) {
-        dowriteln("Unable to find PHP executable (php{$ext}).");
-        exit;
-    }
-    if ($windows_p) {
-               // modify path to help Windows find DLL files
-               $path = dirname($php) . ";" . getenv("PATH");
-               putenv("PATH={$path}");
-    }
-
-    create_compiled_in_modules_list();
-
-    $skip = array(
-                       "CVS" => 1
-                       );
-    $testdirs = array();
-    $tmpfile = array();
-    $tests_in_dir = array();
-
-    register_shutdown_function("delete_tmpfiles");
-
-    $skipped = $failed = $passed = $total = 0;
-}
-
-function &parse_options(&$argc, &$argv)
-{
-    $options = array();
-    while ($argc > 0 && ($opt = substr($argv[0], 0, 2)) == "--") {
-        $opt = array_shift($argv);
-        $argc--;
-        if ($arg == "--") {
-            return $options;
-        }
-        if (ereg('^--([^=]+)=(.*)$', $opt, $matches)) {
-            $opt = $matches[1];
-            $arg = $matches[2];
-        } else {
-            $arg = true;
-        }
-        $options[$opt] = $arg;
-    }
-    return $options;
-}
-
-function do_testing($argc, &$argv)
-{
-    global $term, $windows_p, $php, $skip, $testdirs, $tmpfile, $opts,
-       $skipped, $failed, $passed, $total, $term_bold, $term_norm, $skipped_extensions;
-
-    if ($argc > 1) {
-        if (is_dir($argv[1])) {
-            $dir = $argv[1];
-        } else {
-            for ($i = 1; $i < $argc; $i++) {
-                switch (run_test($argv[$i])) {
-                    case TEST_SKIPPED:
-                    case TEST_INTERNAL_ERROR:
-                        $skipped++;
-                                       break;
-                    case TEST_FAILED:
-                        $failed++;
-                                       break;
-                    case TEST_PASSED:
-                        $passed++;
-                                       break;
-                }
-                $total++;
+        $o = opendir($path) or die("Cannot open directory - $path\n");
+        while ($name = readdir($o)) {
+            if (is_dir("$path/$name")) {
+                if ('.' == $name) continue;
+                if ('..' == $name) continue;
+                if ('CVS' == $name) continue;
+                $directories[] = "$path/$name";
+                continue;
+            }
+            
+            // Cleanup any left-over tmp files from last run.
+            if (ereg('[.]tmp$',$name)) {
+                @unlink("$path/$name");
+                continue;
             }
+            
+            // Otherwise we're only interested in *.phpt files.
+            if (!ereg('[.]phpt$',$name)) continue;
+            //echo "Runnable '" . $name . "' in '" . $path . "'\n";
+            $testfile = realpath("$path/$name");
+            $test_files[] = $testfile;
+            $module_of_test[$testfile] = $module;
         }
-    } else {
-        // $dir = $_ENV["TOP_SRCDIR"]; // XXX ??? where should this variable be set?
-        $dir=str_replace('\\','/',trim(($windows_p ? getenv("TEST_DIR"):`pwd`)));
+        closedir($o);    
     }
-    if (isset($dir) && $dir) {
-        find_testdirs($dir);
+}
 
-        create_found_tests_4_modules_list();
-        create_modules_2_test_list();
+// Run only selected tests, if specified.
 
-        for ($i = 0; $i < sizeof($testdirs); $i++) {
-            run_tests_in_dir($testdirs[$i]);
-        }
+if (count($test_to_run)) {
+    echo "Running selected tests.\n";
+    while (list($name,$runnable) = each($test_to_run)) {
+        echo "test: $name runnable: $runnable\n";
+        if (!$runnable) continue;
+        $test_results[$name] = run_test($php,$name);
     }
+    exit;
+}
 
-    $counting = $total - $skipped;
-
-    if ($counting <= 0) {
-        dowriteln("No tests were run.");
-        return;
-    }
+// We need to know the compiled in modules so we know what to test.
 
-    $total_d = (double)$total;
-    $counting_d = (double)$counting;
-    $passed_p  = 100 * ($passed / $counting_d);
-    $failed_p  = 100 * ($failed / $counting_d);
-    $skipped_p = 100 * ($skipped / $total_d);
-    $passed_pstr = sprintf($passed_p < 10.0 ? "%1.1f" : "%3.0f", $passed_p);
-    $failed_pstr = sprintf($failed_p < 10.0 ? "%1.1f" : "%3.0f", $failed_p);
-    $skipped_pstr = sprintf($skipped_p < 10.0 ? "%1.1f" : "%3.0f", $skipped_p);
-
-    dowriteln("TEST RESULT SUMMARY");
-    dowriteln("=============================");
-    dowriteln(sprintf("Number of tests:  %4d", $total));
-    dowriteln(sprintf("Tests skipped:    %4d (%s%%)", $skipped, $skipped_pstr));
-    dowriteln(sprintf("Tests failed:     %4d (%s%%)", $failed, $failed_pstr));
-    dowriteln(sprintf("Tests passed:     %4d (%s%%)", $passed, $passed_pstr));
-    dowriteln("=============================");
-    dowriteln("Skipped ".sizeof($skipped_extensions)." extensions.");
-       $php_bin_info_cmd = "$php -q -f ".$_ENV["TOP_BUILDDIR"]."/tests/bin-info.inc";
-       system($php_bin_info_cmd);
+$modules_compiled = @get_loaded_extensions();
+$modules_to_test = array(
+    ''      => 1,
+    'PEAR'  => 1,
+);
+foreach ($modules_compiled as $module) {
+    echo "Will test compiled extension: $module\n";
+    $modules_to_test[$module] = 1;
 }
 
-function find_testdirs($dir = '.', $first_pass = true)
-{
-    global $testdirs, $skip;
+echo '
+=====================================================================
+';
 
-    if ($first_pass && is_dir($dir)) {
-        $testdirs[] = $dir;
-    }
-    $dp = @opendir($dir);
-    if (!$dp) {
-        print "Warning: could not open directory $dir\n";
-        return false;
-    }
-    while ($ent = readdir($dp)) {
-        $path = "$dir/$ent";
+sort($test_files);
+$modules_skipped = array();
 
-        if ((isset($skip[$ent]) && $skip[$ent])
-            || substr($ent, 0, 1) == "."
-            || !is_dir($path)
+// Run non-module tests.
 
-            ) {
-            continue;
-               }
+$module_current = '';
+$path_current = '';
+foreach ($test_files as $name) {
 
-        if (strstr("/$path/", "/tests/")) {
-            $testdirs[] = $path;
-        }
-        find_testdirs($path, false);
+    // Only non-module tests wanted for this pass.
+    if ($module_of_test[$name]) continue;   
+    
+    $path = dirname($name);
+    if ($path_current != $path) {
+        $path_current = $path;
+        echo ".... directory $path\n";
     }
-    closedir($dp);
 
+    $test_results[$name] = run_test($php,$name);
 }
 
-function run_tests_in_dir($dir = '.')
-{
-    global $skip, $skipped, $failed, $passed, $total, $opts, $tests_in_dir,$modules_available,$skipped_extensions;
-    $dp = opendir($dir);
-    if (!$dp) {
-        print "Warning: could not run tests in $dir\n";
-        return false;
-    }
-    $testfiles = array();
-    while ($ent = readdir($dp)) {
-        if ((isset($skip[$ent]) && $skip[$ent]) || substr($ent, 0, 1) == "." || substr($ent, -5) != ".phpt") {
-            continue;
-        }
-        $testfiles[] = "$dir/$ent";
-        if(isset($tests_in_dir[$dir]))  $tests_in_dir[$dir]++; else $tests_in_dir[$dir]=1;
+// Run module tests (or at least those applicable to this PHP build).
+
+$module_current = '';
+$path_current = '';
+foreach ($test_files as $name) {
+    $module = $module_of_test[$name];
+    
+    // Already ran non-module tests.
+    if (!$module) continue;     
+
+    if ($module_current != $module) {
+        $module_current = $module;
+        echo "
+---------------------------------------------------------------------
+.... " . ($modules_to_test[$module] ? "testing " : "skipped ") . ($module ? "extension: $module" : "generic PHP") . "
+";
     }
-    closedir($dp);
-    if (isset($tests_in_dir[$dir]) && ($tests_in_dir[$dir] == 0)) {
-        return true;
+    
+    // Can we run the test for the given module?
+    if (!$modules_to_test[$module]) {
+        $modules_skipped[$module] += 1;
+        $test_results[$name] = 'SKIPPED';
+        continue;
     }
-    $oskipped = $skipped;
-    if (sizeof($testfiles) == 0) {
-        return;
+    
+    $path = dirname($name);
+    if ($path_current != $path) {
+        $path_current = $path;
+        echo ".... directory $path\n";
     }
 
-    if ($mod_name=extract_module_name_from_path($dir))   {
-        if ($ext_found=in_array($mod_name,$modules_available))
-                       dowriteln("Testing extension: $mod_name");
-        else $skipped_extensions[$mod_name]=TRUE;
-    }
+    // We've gotten this far - run the test!
+    
+    $test_results[$name] = run_test($php,$name);
+}
 
-    if (!isset($ext_found) or $ext_found!==FALSE) {
-        dowriteln("%bRunning tests in $dir%B");
-        dowriteln("=================".str_repeat("=", strlen($dir)));
-        sort($testfiles);
-        for ($i = 0; $i < sizeof($testfiles); $i++) {
-            switch (run_test($testfiles[$i])) {
-                case TEST_SKIPPED:
-                case TEST_INTERNAL_ERROR:
-                    $skipped++;
-                               break;
-                case TEST_FAILED:
-                    $failed++;
-                               break;
-                case TEST_PASSED:
-                    $passed++;
-                               break;
-            }
-            $total++;
-        }
-        if ($oskipped + (isset($tests_in_dir[$dir])?$tests_in_dir[$dir]:0)  == $skipped) {
-            $skippednow = $skipped - $oskipped;
-            dowriteln("[all $skippednow test(s) skipped]");
-        }
-               dowriteln("");
-    }
+// Summarize results
 
-    return true;
+if (0 == count($test_results)) {
+    echo "No tests were run.\n";
+    return;
 }
 
-function skip_headers($fp)
-{
-    // "cli" version of PHP does not output headers
-    if (php_sapi_name() == "cli") {
-               return;
-    }
-    while (!feof($fp)) {
-        if (trim(fgets($fp, 1024)) == "") {
-            break;
-        }
-    }
+$n_total = count($test_results);
+$sum_results = array();
+foreach ($test_results as $v) {
+    $sum_results[$v]++;
 }
-
-function delete_tmpfiles()
-{
-    global $tmpfile;
-    reset($tmpfile);
-    while (list($k, $v) = each($tmpfile)) {
-        if (file_exists($v)) {
-                       //print "unlink($v): "; var_dump(unlink($v));
-            unlink($v);
-        }
-    }
+$percent_results = array();
+while (list($v,$n) = each($sum_results)) {
+    $percent_results[$v] = (100.0 * $n) / $n_total;
 }
 
-/**
- * Compares two files, ignoring blank lines.
- *
- * @param $file1 string name of first file to compare
- * @param $file2 string name of second file to compare
- *
- * @return bool whether the files were "equal"
- */
-function compare_results($file1, $file2)
+echo "
+=====================================================================
+TIME " . date('Y-m-d H:i:s') . " - end of test run
+
+TEST RESULT SUMMARY
+=====================================================================
+Number of tests : " . sprintf("%4d",$n_total) . "
+Tests skipped   : " . sprintf("%4d (%2.1f%%)",$sum_results['SKIPPED'],$percent_results['SKIPPED']) . "
+Tests failed    : " . sprintf("%4d (%2.1f%%)",$sum_results['FAILED'],$percent_results['FAILED']) . "
+Tests passed    : " . sprintf("%4d (%2.1f%%)",$sum_results['PASSED'],$percent_results['PASSED']) . "
+=====================================================================
+Skipped " . count($modules_skipped) . " extensions
+";
+
+//
+//  Write the given text to a temporary file, and return the filename.
+//
+
+function save_text($filename,$text)
 {
-       $data1 = $data2 = "";
-    if (!($fp1 = @fopen($file1, "r")) || !($fp2 = @fopen($file2, "r"))) {
-        return false;
-    }
-
-    while (!(feof($fp1) || feof($fp2))) {
-        if (!feof($fp1) && trim($line1 = fgets($fp1, 10240)) != "") {
-            //print "adding line1 $line1\n";
+    $fp = @fopen($filename,'w')
+        or die("Cannot open file '" . $filename . "'!\n");
+    fwrite($fp,$text);
+    fclose($fp);
+    if (1 < DETAILED) echo "
+FILE $filename {{{
+$text
+}}} 
+";
+}
 
-            $data1 .= trim($line1);
-        }
-        if (!feof($fp2) && trim($line2 = fgets($fp2, 10240)) != "") {
-            //print "adding line2 $line2\n";
+//
+//  Write an error in a format recognizable to Emacs or MSVC.
+//
 
-            $data2 .= trim($line2);
-        }
-    }
-    fclose($fp1);
-    fclose($fp2);
-    if ((trim($data1) != trim($data2))
-        || ($data1=='' && $data2=='')) {
-               //print "data1=";var_dump($data1);
-               //print "data2=";var_dump($data2);
-        return false;
+function error_report($testname,$logname,$tested) 
+{
+    $testname = realpath($testname);
+    $logname  = realpath($logname);
+    switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) {
+    case 'MSVC':
+        echo $testname . "(1) : $tested\n";
+        echo $logname . "(1) :  $tested\n";
+        break;
+    case 'EMACS':
+        echo $testname . ":1: $tested\n";
+        echo $logname . ":1:  $tested\n";
+        break;
     }
-    return true;
 }
 
-function run_test($file)
-{
-    global $php, $tmpfile, $term_bold, $term_norm, $term, $windows_p;
+//
+//  Run an individual test case.
+//
 
-    $variables = array("TEST", "POST", "GET", "FILE", "EXPECT", "SKIPIF",
-                       "OUTPUT");
-    $fp = @fopen($file, "r");
-    if (!$fp) {
-        return TEST_INTERNAL_ERROR;
-    }
-    $tmpdir = dirname($file);
-    $tmpfix = "phpt.";
-    $tmpfile["FILE"] = tempnam($tmpdir, $tmpfix);
-    $tmpfile["SKIPIF"] = tempnam($tmpdir, $tmpfix);
-    $tmpfile["POST"] = tempnam($tmpdir, $tmpfix);
-
-    $tmpfile["EXPECT"] = tempnam($tmpdir, $tmpfix);
-    $tmpfile["OUTPUT"] = tempnam($tmpdir, $tmpfix);
-
-
-    while ($line = fgets($fp, 4096)) {
-        if (ereg('^--([A-Z]+)--', $line, $matches)) {
-            $var = $matches[1];
-            if (isset($tmpfile[$var]) && $tmpfile[$var]) {
-                $fps[$var] = @fopen($tmpfile[$var], "w");
-            } else {
-                $$var = '';
-            }
-        } else {
-            if (isset($var) && $var) {
-                if ($var == "POST") {
-                    $line = trim($line);
-                }
-                if (isset($fps[$var]) && $fps[$var]) {
-                    fwrite($fps[$var], $line);
-                } else {
-                    $$var .= $line;
-                }
-            }
+function run_test($php,$file)
+{
+    if (DETAILED) echo "
+=================
+TEST $file
+";
+
+    // Load the sections of the test file.
+    
+    $section_text = array(
+        'TEST'      => '(unnamed test)',
+        'SKIPIF'    => '',
+        'GET'       => '',
+    );
+
+    $fp = @fopen($file, "r")
+        or die("Cannot open test file: $file\n");
+
+    $section = '';
+    while (!feof($fp)) {
+        $line = fgets($fp);
+        
+        // Match the beginning of a section.
+        if (ereg('^--([A-Z]+)--',$line,$r)) {
+            $section = $r[1];
+            $section_text[$section] = '';
+            continue;
         }
+        
+        // Add to the section text.
+        $section_text[$section] .= $line;
     }
-    if(isset($fps) && is_array($fps)) {
-        reset($fps);
-        while (list($k, $v) = each($fps)) {
-            if (is_resource($v)) {
-                fclose($v);
-            }
+    fclose($fp);
+
+    $tmp = dirname($file);
+    $tmp_skipif = realpath("$tmp/_SKIPIF");  
+    $tmp_file   = realpath("$tmp/_FILE");  
+    $tmp_post   = realpath("$tmp/_POST");  
+    
+    @unlink($tmp_skipif);
+    @unlink($tmp_file);
+    @unlink($tmp_post);
+    
+    // Reset environment from any previous test.
+
+    putenv("REDIRECT_STATUS=");
+    putenv("QUERY_STRING=");
+    putenv("PATH_TRANSLATED=");
+    putenv("SCRIPT_FILENAME=");
+    putenv("REQUEST_METHOD=");
+    putenv("CONTENT_TYPE=");
+    putenv("CONTENT_LENGTH=");
+    
+    // Check if test should be skipped.
+    
+    if (trim($section_text['SKIPIF'])) {
+        save_text($tmp_skipif,$section_text['SKIPIF']);
+        $output = `$php -f $tmp_skipif`;
+        @unlink($tmp_skipif);
+        $output = trim($output);
+        if (0 == strcmp('skip',$output)) {
+            return 'SKIPPED';
         }
     }
-    putenv("PHP_TEST=1");
+    
+    // We've satisfied the preconditions - run the test!
+    
+    save_text($tmp_file,$section_text['FILE']);
+    $query_string = trim($section_text['GET']);
+
     putenv("REDIRECT_STATUS=1");
-    putenv("CONTENT_LENGTH=");
-    putenv("QUERY_STRING=".(isset($GET)?$GET:""));
-    $include_path = ini_get("include_path");
-    if (isset($fps["SKIPIF"])) {
-        $tmpfile["SKIPIF_OUTPUT"] = tempnam($tmpdir, $tmpfix);
+    putenv("QUERY_STRING=$query_string");
+    putenv("PATH_TRANSLATED=$tmp_file");
+    putenv("SCRIPT_FILENAME=$tmp_file");
+
+    if (isset($section_text['POST'])) {
+    
+        $post = trim($section_text['POST']);
+        save_text($tmp_post,$post);
+        $content_length = strlen($post);
+        
+        putenv("REQUEST_METHOD=POST");
+        putenv("CONTENT_TYPE=application/x-www-form-urlencoded");
+        putenv("CONTENT_LENGTH=$content_length");
+        
+        $cmd = "$php 2>&1 < $tmp_post";
+        
+    } else {
+    
         putenv("REQUEST_METHOD=GET");
         putenv("CONTENT_TYPE=");
-        putenv("PATH_TRANSLATED=$tmpfile[SKIPIF]");
-        putenv("SCRIPT_FILENAME=$tmpfile[SKIPIF]");
-        $skipifcmd = "$php -q -f $tmpfile[SKIPIF] > $tmpfile[SKIPIF_OUTPUT]";
-        system($skipifcmd, $ret);
-        $sp = @fopen($tmpfile["SKIPIF_OUTPUT"], "r");
-        if ($sp) {
-            skip_headers($sp);
-            $skip = trim(fgets($sp, 1024));
-            fclose($sp);
-            if ($skip == "skip") {
-                delete_tmpfiles();
-                               return TEST_SKIPPED;
-                       }
-               }
-       }
-       putenv("PATH_TRANSLATED=$tmpfile[FILE]");
-       putenv("SCRIPT_FILENAME=$tmpfile[FILE]");
-       if (isset($fps["POST"])) {
-               putenv("REQUEST_METHOD=POST");
-               putenv("CONTENT_TYPE=application/x-www-form-urlencoded");
-               putenv("CONTENT_LENGTH=".filesize($tmpfile["POST"]));
-       } else {
-               putenv("REQUEST_METHOD=GET");
-               putenv("CONTENT_TYPE=");
-               putenv("CONTENT_LENGTH=");
-       }
-       if (isset($fps["POST"])) {
-               if(!$windows_p) {
-                       $cmd = "2>&1 $php -q $tmpfile[FILE] < $tmpfile[POST]";
-               }
-               else {
-                       $cmd = "$term /c " . realpath($php) ." -q $tmpfile[FILE] < $tmpfile[POST]";
-               }
-       } else {
-               if(!$windows_p) {
-                       $cmd = "2>&1 $php -q $tmpfile[FILE]";
-               }
-               else {
-                       $cmd = "$term /c " . realpath($php) ." -q $tmpfile[FILE]";;
-               }
-       }
-       $ofp = @fopen($tmpfile["OUTPUT"], "w");
-       if (!$ofp) {
-               dowriteln("Error: could not write to output file");
-               delete_tmpfiles();
-               return TEST_INTERNAL_ERROR;
-       }
-       $cp = popen($cmd, "r");
-       if (!$cp) {
-               dowriteln("Error: could not execute: $cmd");
-               delete_tmpfiles();
-               return TEST_INTERNAL_ERROR;
-       }
-       skip_headers($cp);
-       while ($data = fread($cp, 2048)) {
-               fwrite($ofp, $data);
-       }
-       fclose($ofp);
-       pclose($cp);
-       $desc = isset($TEST)?trim($TEST):"";
-       $outfile = ereg_replace('\.phpt$', '.out', $file);
-       $expectfile = ereg_replace('\.phpt$', '.exp', $file);
-       $phpfile = ereg_replace('\.phpt$', '.php', $file);
-       if (compare_results($tmpfile["OUTPUT"], $tmpfile["EXPECT"])) {
-               $status = TEST_PASSED;
-               $text = "passed";
-               $pre = $post = "";
-               if (file_exists($outfile)) {
-                       unlink($outfile);
-               }
-               if (file_exists($expectfile)) {
-                       unlink($expectfile);
-               }
-               if (file_exists($phpfile)) {
-                       unlink($phpfile);
-               }
-       } else {
-               //system("env");
-               $status = TEST_FAILED;
-               $text = "failed";
-               $pre = $term_bold;
-               $post = $term_norm;
-               $desc .= " (".basename($file).")";
-               if (file_exists($outfile)) {
-                       unlink($outfile);
-               }
-               copy($tmpfile["OUTPUT"], $outfile);
-               copy($tmpfile["EXPECT"], $expectfile);
-               copy($tmpfile["FILE"], $phpfile);
-       }
-       dowriteln(sprintf("%s%-68s ... %s%s", $pre, substr($desc, 0, 68),
-                                         $text, $post));
-//       if ($status == TEST_FAILED) {
-//               for ($i = 0; $i < sizeof($variables); $i++) {
-//                       $var = $variables[$i];
-//                       print "$var:\n";
-//                       if ($tmpfile[$var]) {
-//                               if (file_exists($tmpfile[$var])) {
-//                                       system("cat ".$tmpfile[$var]);
-//                               }
-//                       } else {
-//                               print $$var;
-//                       }
-//               }
-//               print "--\n\n";
-//       }
-       delete_tmpfiles();
-       return $status;
+        putenv("CONTENT_LENGTH=");
+
+        $cmd = "$php 2>&1";
+        
+    }
+
+    if (DETAILED) echo "
+CONTENT_LENGTH  = " . getenv("CONTENT_LENGTH") . "
+CONTENT_TYPE    = " . getenv("CONTENT_TYPE") . "
+PATH_TRANSLATED = " . getenv("PATH_TRANSLATED") . "
+QUERY_STRING    = " . getenv("QUERY_STRING") . "
+REDIRECT_STATUS = " . getenv("REDIRECT_STATUS") . "
+REQUEST_METHOD  = " . getenv("REQUEST_METHOD") . "
+SCRIPT_FILENAME = " . getenv("SCRIPT_FILENAME") . "
+COMMAND $cmd
+";
+    
+    $out = `$cmd`;
+    
+    @unlink($tmp_post);
+    @unlink($tmp_file);
+    
+    // Does the output match what is expected?
+
+    $tested = trim($section_text['TEST']);
+    
+    $output = trim(preg_replace('/^(..+\n)+\n/','',$out));
+    $wanted = trim($section_text['EXPECT']);
+    
+    $output = preg_replace('/\r\n/',"\n",$output);
+    $wanted = preg_replace('/\r\n/',"\n",$wanted);
+
+    $ok = (0 == strcmp($output,$wanted));
+    if ($ok) {
+        echo "PASS $tested\n";
+        return 'PASSED';
+    }
+    
+    // Test failed so we need to report details.
+
+    echo "FAIL $tested (" . basename($file) . ").\n";
+
+    $logname = ereg_replace('\.phpt$','.log',$file);
+    $log = fopen($logname,'w')
+        or die("Cannot create test log - $logname\n");
+    
+    fwrite($log,"
+---- EXPECTED OUTPUT
+$wanted
+---- ACTUAL OUTPUT
+$output
+---- FAILED
+");
+    fclose($log);
+
+    error_report($file,$logname,$tested);
+    
+    return 'FAILED';
 }
 
 /*