summaryrefslogtreecommitdiff
path: root/run-tests.php
diff options
context:
space:
mode:
authorMax Semenik <maxsem.wiki@gmail.com>2021-02-10 15:17:03 +0300
committerNikita Popov <nikita.ppv@gmail.com>2021-03-16 11:51:55 +0100
commit9140c9038a83ff55a78f357f8485de086d83d94e (patch)
treea40b6d3591df574e8292aaae6a56c4818483a250 /run-tests.php
parent77ebf81492e8d9dcd441894cea9e6efdc8d1011a (diff)
downloadphp-git-9140c9038a83ff55a78f357f8485de086d83d94e.tar.gz
run-tests.php: class for test file loading
This moves a bunch of code outside of run_tests(), making it a bit more manageable. Additionally, accessors provide better readability than isset() and friends. This is a minimal patch that moves the code but does not refactor much. For the sake of reviewing experience, it does not involve further refactoring which could include: * Removing setSection() * Fixing up the mess with hasSection() vs. sectionNotEmpty(), only one of which is really needed. * Moving more repetitive code into the new class. All of this will be done with later commits. Closes GH-6678.
Diffstat (limited to 'run-tests.php')
-rwxr-xr-xrun-tests.php596
1 files changed, 345 insertions, 251 deletions
diff --git a/run-tests.php b/run-tests.php
index c04d2f4a97..825718407c 100755
--- a/run-tests.php
+++ b/run-tests.php
@@ -1862,141 +1862,36 @@ TEST $file
";
}
- // Load the sections of the test file.
- $section_text = ['TEST' => ''];
-
- $fp = fopen($file, "rb") or error("Cannot open test file: $file");
-
- $bork_info = null;
-
- if (!feof($fp)) {
- $line = fgets($fp);
-
- if ($line === false) {
- $bork_info = "cannot read test";
- }
- } else {
- $bork_info = "empty test [$file]";
- }
- if ($bork_info === null && strncmp('--TEST--', $line, 8)) {
- $bork_info = "tests must start with --TEST-- [$file]";
- }
-
- $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 = (string) $r[1];
-
- if (isset($section_text[$section]) && $section_text[$section]) {
- $bork_info = "duplicated $section section";
- }
-
- // check for unknown sections
- if (!in_array($section, [
- 'EXPECT', 'EXPECTF', 'EXPECTREGEX', 'EXPECTREGEX_EXTERNAL', 'EXPECT_EXTERNAL', 'EXPECTF_EXTERNAL', 'EXPECTHEADERS',
- 'POST', 'POST_RAW', 'GZIP_POST', 'DEFLATE_POST', 'PUT', 'GET', 'COOKIE', 'ARGS',
- 'FILE', 'FILEEOF', 'FILE_EXTERNAL', 'REDIRECTTEST',
- 'CAPTURE_STDIO', 'STDIN', 'CGI', 'PHPDBG',
- 'INI', 'ENV', 'EXTENSIONS',
- 'SKIPIF', 'XFAIL', 'XLEAK', 'CLEAN',
- 'CREDITS', 'DESCRIPTION', 'CONFLICTS', 'WHITESPACE_SENSITIVE',
- ])) {
- $bork_info = 'Unknown section "' . $section . '"';
- }
-
- $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;
- }
- }
-
$shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $file);
$tested_file = $shortname;
- $tested = trim($section_text['TEST']);
-
- // the redirect section allows a set of tests to be reused outside of
- // a given test dir
- if ($bork_info === null) {
- if (isset($section_text['REDIRECTTEST'])) {
- if ($IN_REDIRECT) {
- $bork_info = "Can't redirect a test from within a redirected test";
- }
- } else {
- if (!isset($section_text['PHPDBG']) && isset($section_text['FILE']) + isset($section_text['FILEEOF']) + isset($section_text['FILE_EXTERNAL']) != 1) {
- $bork_info = "missing section --FILE--";
- }
-
- if (isset($section_text['FILEEOF'])) {
- $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']);
- unset($section_text['FILEEOF']);
- }
-
- if ($num_repeats > 1 && isset($section_text['FILE_EXTERNAL'])) {
- return skip_test($tested, $tested_file, $shortname, 'Test with FILE_EXTERNAL might not be repeatable');
- }
-
- foreach (['FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX'] as $prefix) {
- $key = $prefix . '_EXTERNAL';
-
- if (isset($section_text[$key])) {
- // don't allow tests to retrieve files from anywhere but this subdirectory
- $section_text[$key] = dirname($file) . '/' . trim(str_replace('..', '', $section_text[$key]));
- if (file_exists($section_text[$key])) {
- $section_text[$prefix] = file_get_contents($section_text[$key]);
- unset($section_text[$key]);
- } else {
- $bork_info = "could not load --" . $key . "-- " . dirname($file) . '/' . trim($section_text[$key]);
- }
- }
- }
-
- if ((isset($section_text['EXPECT']) + isset($section_text['EXPECTF']) + isset($section_text['EXPECTREGEX'])) != 1) {
- $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
- }
- }
- }
- fclose($fp);
-
- if ($bork_info !== null) {
- show_result("BORK", $bork_info, $tested_file);
+ try {
+ $test = new TestFile($file, (bool)$IN_REDIRECT);
+ } catch (BorkageException $ex) {
+ show_result("BORK", $ex->getMessage(), $tested_file);
$PHP_FAILED_TESTS['BORKED'][] = [
'name' => $file,
'test_name' => '',
'output' => '',
'diff' => '',
- 'info' => "$bork_info [$file]",
+ 'info' => "{$ex->getMessage()} [$file]",
];
- $junit->markTestAs('BORK', $shortname, $tested_file, 0, $bork_info);
+ $junit->markTestAs('BORK', $shortname, $tested_file, 0, $ex->getMessage());
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;
+ $tested = $test->getName();
+
+ if ($num_repeats > 1 && $test->hasSection('FILE_EXTERNAL')) {
+ return skip_test($tested, $tested_file, $shortname, 'Test with FILE_EXTERNAL might not be repeatable');
+ }
+
+ if ($test->hasSection('CAPTURE_STDIO')) {
+ $capture = $test->getSection('CAPTURE_STDIO');
+ $captureStdIn = stripos($capture, 'STDIN') !== false;
+ $captureStdOut = stripos($capture, 'STDOUT') !== false;
+ $captureStdErr = stripos($capture, 'STDERR') !== false;
} else {
$captureStdIn = true;
$captureStdOut = true;
@@ -2009,7 +1904,7 @@ TEST $file
}
/* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */
- if (array_key_exists('CGI', $section_text) || !empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['GZIP_POST']) || !empty($section_text['DEFLATE_POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['PUT']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) {
+ if ($test->isCGI()) {
if (!$php_cgi) {
return skip_test($tested, $tested_file, $shortname, 'CGI not available');
}
@@ -2022,11 +1917,7 @@ TEST $file
/* For phpdbg tests, check if phpdbg sapi is available and if it is, use it. */
$extra_options = '';
- if (array_key_exists('PHPDBG', $section_text)) {
- if (!isset($section_text['STDIN'])) {
- $section_text['STDIN'] = $section_text['PHPDBG'] . "\n";
- }
-
+ if ($test->hasSection('PHPDBG')) {
if (isset($phpdbg)) {
$php = $phpdbg . ' -qIb';
@@ -2042,13 +1933,13 @@ TEST $file
}
if ($num_repeats > 1) {
- if (array_key_exists('CLEAN', $section_text)) {
+ if ($test->hasSection('CLEAN')) {
return skip_test($tested, $tested_file, $shortname, 'Test with CLEAN might not be repeatable');
}
- if (array_key_exists('STDIN', $section_text)) {
+ if ($test->hasSection('STDIN')) {
return skip_test($tested, $tested_file, $shortname, 'Test with STDIN might not be repeatable');
}
- if (array_key_exists('CAPTURE_STDIO', $section_text)) {
+ if ($test->hasSection('CAPTURE_STDIO')) {
return skip_test($tested, $tested_file, $shortname, 'Test with CAPTURE_STDIO might not be repeatable');
}
}
@@ -2095,8 +1986,8 @@ TEST $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']);
+ if ($test->hasSection('FILE')) {
+ save_text($copy_file, $test->getSection('FILE'));
}
$temp_filenames = [
@@ -2114,7 +2005,7 @@ TEST $file
}
if (is_array($IN_REDIRECT)) {
- $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']);
+ $tested = $IN_REDIRECT['prefix'] . ' ' . $tested;
$tested_file = $tmp_relative_file;
$shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $tested_file);
}
@@ -2145,8 +2036,8 @@ TEST $file
$env['CONTENT_LENGTH'] = '';
$env['TZ'] = '';
- if (!empty($section_text['ENV'])) {
- foreach (explode("\n", trim($section_text['ENV'])) as $e) {
+ if ($test->sectionNotEmpty('ENV')) {
+ foreach (explode("\n", $test->getSection('ENV')) as $e) {
$e = explode('=', trim($e), 2);
if (!empty($e[0]) && isset($e[1])) {
@@ -2159,11 +2050,11 @@ TEST $file
$ini_settings = $workerID ? ['opcache.cache_id' => "worker$workerID"] : [];
// Additional required extensions
- if (array_key_exists('EXTENSIONS', $section_text)) {
+ if ($test->hasSection('EXTENSIONS')) {
$ext_params = [];
settings2array($ini_overwrites, $ext_params);
$ext_params = settings2params($ext_params);
- $extensions = preg_split("/[\n\r]+/", trim($section_text['EXTENSIONS']));
+ $extensions = preg_split("/[\n\r]+/", trim($test->getSection('EXTENSIONS')));
[$ext_dir, $loaded] = $skipCache->getExtensions("$php $pass_options $extra_options $ext_params $no_file_cache");
$ext_prefix = IS_WINDOWS ? "php_" : "";
foreach ($extensions as $req_ext) {
@@ -2201,12 +2092,12 @@ TEST $file
// Any special ini settings
// these may overwrite the test defaults...
- if (array_key_exists('INI', $section_text)) {
- $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
- $section_text['INI'] = str_replace('{TMP}', sys_get_temp_dir(), $section_text['INI']);
+ if ($test->hasSection('INI')) {
+ $ini = str_replace('{PWD}', dirname($file), $test->getSection('INI'));
+ $ini = str_replace('{TMP}', sys_get_temp_dir(), $ini);
$replacement = IS_WINDOWS ? '"' . PHP_BINARY . ' -r \"while ($in = fgets(STDIN)) echo $in;\" > $1"' : 'tee $1 >/dev/null';
- $section_text['INI'] = preg_replace('/{MAIL:(\S+)}/', $replacement, $section_text['INI']);
- settings2array(preg_split("/[\n\r]+/", $section_text['INI']), $ini_settings);
+ $ini = preg_replace('/{MAIL:(\S+)}/', $replacement, $ini);
+ settings2array(preg_split("/[\n\r]+/", $ini), $ini_settings);
if ($num_repeats > 1 && isset($ini_settings['opcache.opt_debug_level'])) {
return skip_test($tested, $tested_file, $shortname, 'opt_debug_level tests are not repeatable');
@@ -2221,89 +2112,89 @@ TEST $file
$info = '';
$warn = false;
- if (array_key_exists('SKIPIF', $section_text)) {
- if (trim($section_text['SKIPIF'])) {
- show_file_block('skip', $section_text['SKIPIF']);
- $extra = !IS_WINDOWS ?
- "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
+ if ($test->sectionNotEmpty('SKIPIF')) {
+ show_file_block('skip', $test->getSection('SKIPIF'));
+ $extra = !IS_WINDOWS ?
+ "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
- if ($valgrind) {
- $env['USE_ZEND_ALLOC'] = '0';
- $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
- }
+ if ($valgrind) {
+ $env['USE_ZEND_ALLOC'] = '0';
+ $env['ZEND_DONT_UNLOAD_MODULES'] = 1;
+ }
- $junit->startTimer($shortname);
+ $junit->startTimer($shortname);
- $startTime = microtime(true);
- $commandLine = "$extra $php $pass_options $extra_options -q $orig_ini_settings $no_file_cache -d display_errors=1 -d display_startup_errors=0";
- $output = $skipCache->checkSkip($commandLine, $section_text['SKIPIF'], $test_skipif, $temp_skipif, $env);
+ $startTime = microtime(true);
+ $commandLine = "$extra $php $pass_options $extra_options -q $orig_ini_settings $no_file_cache -d display_errors=1 -d display_startup_errors=0";
+ $output = $skipCache->checkSkip($commandLine, $test->getSection('SKIPIF'), $test_skipif, $temp_skipif, $env);
- $time = microtime(true) - $startTime;
+ $time = microtime(true) - $startTime;
+ $junit->stopTimer($shortname);
- $junit->stopTimer($shortname);
+ if ($time > $slow_min_ms / 1000) {
+ $PHP_FAILED_TESTS['SLOW'][] = [
+ 'name' => $file,
+ 'test_name' => 'SKIPIF of ' . $tested . " [$tested_file]",
+ 'output' => '',
+ 'diff' => '',
+ 'info' => $time,
+ ];
+ }
- if ($time > $slow_min_ms / 1000) {
- $PHP_FAILED_TESTS['SLOW'][] = [
- 'name' => $file,
- 'test_name' => 'SKIPIF of ' . $tested . " [$tested_file]",
- 'output' => '',
- 'diff' => '',
- 'info' => $time,
- ];
+ if (!$cfg['keep']['skip']) {
+ @unlink($test_skipif);
+ }
+
+ if (!strncasecmp('skip', $output, 4)) {
+ if (preg_match('/^skip\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 (!strncasecmp('skip', $output, 4)) {
- if (preg_match('/^skip\s*(.+)/i', $output, $m)) {
- show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames);
- } else {
- show_result('SKIP', $tested, $tested_file, '', $temp_filenames);
- }
+ $message = !empty($m[1]) ? $m[1] : '';
+ $junit->markTestAs('SKIP', $shortname, $tested, null, $message);
+ return 'SKIPPED';
+ }
- $message = !empty($m[1]) ? $m[1] : '';
- $junit->markTestAs('SKIP', $shortname, $tested, null, $message);
- return 'SKIPPED';
- }
- if (!strncasecmp('info', $output, 4) && preg_match('/^info\s*(.+)/i', $output, $m)) {
- $info = " (info: $m[1])";
- } elseif (!strncasecmp('warn', $output, 4) && preg_match('/^warn\s+(.+)/i', $output, $m)) {
- $warn = true; /* only if there is a reason */
- $info = " (warn: $m[1])";
- } elseif (!strncasecmp('xfail', $output, 5)) {
- // Pretend we have an XFAIL section
- $section_text['XFAIL'] = ltrim(substr($output, 5));
- } elseif ($output !== '') {
- show_result("BORK", $output, $tested_file, 'reason: invalid output from SKIPIF', $temp_filenames);
- $PHP_FAILED_TESTS['BORKED'][] = [
- 'name' => $file,
- 'test_name' => '',
- 'output' => '',
- 'diff' => '',
- 'info' => "$output [$file]",
- ];
+ if (!strncasecmp('info', $output, 4) && preg_match('/^info\s*(.+)/i', $output, $m)) {
+ $info = " (info: $m[1])";
+ } elseif (!strncasecmp('warn', $output, 4) && preg_match('/^warn\s+(.+)/i', $output, $m)) {
+ $warn = true; /* only if there is a reason */
+ $info = " (warn: $m[1])";
+ } elseif (!strncasecmp('xfail', $output, 5)) {
+ // Pretend we have an XFAIL section
+ $test->setSection('XFAIL', ltrim(substr($output, 5)));
+ } elseif ($output !== '') {
+ show_result("BORK", $output, $tested_file, 'reason: invalid output from SKIPIF', $temp_filenames);
+ $PHP_FAILED_TESTS['BORKED'][] = [
+ 'name' => $file,
+ 'test_name' => '',
+ 'output' => '',
+ 'diff' => '',
+ 'info' => "$output [$file]",
+ ];
- $junit->markTestAs('BORK', $shortname, $tested, null, $output);
- return 'BORKED';
- }
+ $junit->markTestAs('BORK', $shortname, $tested, null, $output);
+ return 'BORKED';
}
}
- if (!extension_loaded("zlib")
- && (array_key_exists("GZIP_POST", $section_text)
- || array_key_exists("DEFLATE_POST", $section_text))) {
+ if (!extension_loaded("zlib") && $test->hasAnySections("GZIP_POST", "DEFLATE_POST")) {
$message = "ext/zlib required";
show_result('SKIP', $tested, $tested_file, "reason: $message", $temp_filenames);
$junit->markTestAs('SKIP', $shortname, $tested, null, $message);
return 'SKIPPED';
}
- if (isset($section_text['REDIRECTTEST'])) {
+ if ($test->hasSection('REDIRECTTEST')) {
$test_files = [];
- $IN_REDIRECT = eval($section_text['REDIRECTTEST']);
+ $IN_REDIRECT = eval($test->getSection('REDIRECTTEST'));
$IN_REDIRECT['via'] = "via [$shortname]\n\t";
$IN_REDIRECT['dir'] = realpath(dirname($file));
- $IN_REDIRECT['prefix'] = trim($section_text['TEST']);
+ $IN_REDIRECT['prefix'] = $tested;
if (!empty($IN_REDIRECT['TESTS'])) {
if (is_array($org_file)) {
@@ -2348,7 +2239,7 @@ TEST $file
}
}
- if (is_array($org_file) || isset($section_text['REDIRECTTEST'])) {
+ if (is_array($org_file) || $test->hasSection('REDIRECTTEST')) {
if (is_array($org_file)) {
$file = $org_file[0];
}
@@ -2369,15 +2260,15 @@ TEST $file
}
// 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);
+ if ($test->hasSection('FILE')) {
+ show_file_block('php', $test->getSection('FILE'), 'TEST');
+ save_text($test_file, $test->getSection('FILE'), $temp_file);
} else {
$test_file = $temp_file = "";
}
- if (array_key_exists('GET', $section_text)) {
- $query_string = trim($section_text['GET']);
+ if ($test->hasSection('GET')) {
+ $query_string = trim($test->getSection('GET'));
} else {
$query_string = '';
}
@@ -2393,13 +2284,13 @@ TEST $file
$env['SCRIPT_FILENAME'] = $test_file;
}
- if (array_key_exists('COOKIE', $section_text)) {
- $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
+ if ($test->hasSection('COOKIE')) {
+ $env['HTTP_COOKIE'] = trim($test->getSection('COOKIE'));
} else {
$env['HTTP_COOKIE'] = '';
}
- $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : '';
+ $args = $test->hasSection('ARGS') ? ' -- ' . $test->getSection('ARGS') : '';
if ($preload && !empty($test_file)) {
save_text($preload_filename, "<?php opcache_compile_file('$test_file');");
@@ -2409,8 +2300,8 @@ TEST $file
$pass_options .= " -d opcache.preload=" . $preload_filename;
}
- if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
- $post = trim($section_text['POST_RAW']);
+ if ($test->sectionNotEmpty('POST_RAW')) {
+ $post = trim($test->getSection('POST_RAW'));
$raw_lines = explode("\n", $post);
$request = '';
@@ -2440,8 +2331,8 @@ TEST $file
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']);
+ } elseif ($test->sectionNotEmpty('PUT')) {
+ $post = trim($test->getSection('PUT'));
$raw_lines = explode("\n", $post);
$request = '';
@@ -2471,8 +2362,8 @@ TEST $file
save_text($tmp_post, $request);
$cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\"";
- } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
- $post = trim($section_text['POST']);
+ } elseif ($test->sectionNotEmpty('POST')) {
+ $post = trim($test->getSection('POST'));
$content_length = strlen($post);
save_text($tmp_post, $post);
@@ -2486,8 +2377,8 @@ TEST $file
}
$cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\"";
- } elseif (array_key_exists('GZIP_POST', $section_text) && !empty($section_text['GZIP_POST'])) {
- $post = trim($section_text['GZIP_POST']);
+ } elseif ($test->sectionNotEmpty('GZIP_POST')) {
+ $post = trim($test->getSection('GZIP_POST'));
$post = gzencode($post, 9, FORCE_GZIP);
$env['HTTP_CONTENT_ENCODING'] = 'gzip';
@@ -2499,8 +2390,8 @@ TEST $file
$env['CONTENT_LENGTH'] = $content_length;
$cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\"";
- } elseif (array_key_exists('DEFLATE_POST', $section_text) && !empty($section_text['DEFLATE_POST'])) {
- $post = trim($section_text['DEFLATE_POST']);
+ } elseif ($test->sectionNotEmpty('DEFLATE_POST')) {
+ $post = trim($test->getSection('DEFLATE_POST'));
$post = gzcompress($post, 9);
$env['HTTP_CONTENT_ENCODING'] = 'deflate';
save_text($tmp_post, $post);
@@ -2546,7 +2437,8 @@ COMMAND $cmd
$hrtime = hrtime();
$startTime = $hrtime[0] * 1000000000 + $hrtime[1];
- $out = system_with_timeout($cmd, $env, $section_text['STDIN'] ?? null, $captureStdIn, $captureStdOut, $captureStdErr);
+ $stdin = $test->hasSection('STDIN') ? $test->getSection('STDIN') : null;
+ $out = system_with_timeout($cmd, $env, $stdin, $captureStdIn, $captureStdOut, $captureStdErr);
$junit->stopTimer($shortname);
$hrtime = hrtime();
@@ -2561,20 +2453,18 @@ COMMAND $cmd
];
}
- 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 ($test->sectionNotEmpty('CLEAN') && (!$no_clean || $cfg['keep']['clean'])) {
+ show_file_block('clean', $test->getSection('CLEAN'));
+ save_text($test_clean, trim($test->getSection('CLEAN')), $temp_clean);
- if (!$no_clean) {
- $extra = !IS_WINDOWS ?
- "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
- system_with_timeout("$extra $php $pass_options $extra_options -q $orig_ini_settings $no_file_cache \"$test_clean\"", $env);
- }
+ if (!$no_clean) {
+ $extra = !IS_WINDOWS ?
+ "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : "";
+ system_with_timeout("$extra $php $pass_options $extra_options -q $orig_ini_settings $no_file_cache \"$test_clean\"", $env);
+ }
- if (!$cfg['keep']['clean']) {
- @unlink($test_clean);
- }
+ if (!$cfg['keep']['clean']) {
+ @unlink($test_clean);
}
}
@@ -2630,10 +2520,10 @@ COMMAND $cmd
$failed_headers = false;
- if (isset($section_text['EXPECTHEADERS'])) {
+ if ($test->hasSection('EXPECTHEADERS')) {
$want = [];
$wanted_headers = [];
- $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']);
+ $lines = preg_split("/[\n\r]+/", $test->getSection('EXPECTHEADERS'));
foreach ($lines as $line) {
if (strpos($line, ':') !== false) {
@@ -2667,17 +2557,17 @@ COMMAND $cmd
$output = trim(preg_replace("/\n?Warning: Can't preload [^\n]*\n?/", "", $output));
}
- if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
- if (isset($section_text['EXPECTF'])) {
- $wanted = trim($section_text['EXPECTF']);
+ if ($test->hasAnySections('EXPECTF', 'EXPECTREGEX')) {
+ if ($test->hasSection('EXPECTF')) {
+ $wanted = trim($test->getSection('EXPECTF'));
} else {
- $wanted = trim($section_text['EXPECTREGEX']);
+ $wanted = trim($test->getSection('EXPECTREGEX'));
}
show_file_block('exp', $wanted);
$wanted_re = preg_replace('/\r\n/', "\n", $wanted);
- if (isset($section_text['EXPECTF'])) {
+ if ($test->hasSection('EXPECTF')) {
// do preg_quote, but miss out any %r delimited sections
$temp = "";
$r = "%r";
@@ -2729,10 +2619,10 @@ COMMAND $cmd
@unlink($tmp_post);
if (!$leaked && !$failed_headers) {
- if (isset($section_text['XFAIL'])) {
+ if ($test->hasSection('XFAIL')) {
$warn = true;
$info = " (warn: XFAIL section but test passes)";
- } elseif (isset($section_text['XLEAK'])) {
+ } elseif ($test->hasSection('XLEAK')) {
$warn = true;
$info = " (warn: XLEAK section but test passes)";
} else {
@@ -2743,7 +2633,7 @@ COMMAND $cmd
}
}
} else {
- $wanted = trim($section_text['EXPECT']);
+ $wanted = trim($test->getSection('EXPECT'));
$wanted = preg_replace('/\r\n/', "\n", $wanted);
show_file_block('exp', $wanted);
@@ -2757,10 +2647,10 @@ COMMAND $cmd
@unlink($tmp_post);
if (!$leaked && !$failed_headers) {
- if (isset($section_text['XFAIL'])) {
+ if ($test->hasSection('XFAIL')) {
$warn = true;
$info = " (warn: XFAIL section but test passes)";
- } elseif (isset($section_text['XLEAK'])) {
+ } elseif ($test->hasSection('XLEAK')) {
$warn = true;
$info = " (warn: XLEAK section but test passes)";
} else {
@@ -2786,7 +2676,7 @@ COMMAND $cmd
}
if ($leaked) {
- $restype[] = isset($section_text['XLEAK']) ?
+ $restype[] = $test->hasSection('XLEAK') ?
'XLEAK' : 'LEAK';
}
@@ -2795,12 +2685,12 @@ COMMAND $cmd
}
if (!$passed) {
- if (isset($section_text['XFAIL'])) {
+ if ($test->hasSection('XFAIL')) {
$restype[] = 'XFAIL';
- $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']);
- } elseif (isset($section_text['XLEAK'])) {
+ $info = ' XFAIL REASON: ' . rtrim($test->getSection('XFAIL'));
+ } elseif ($test->hasSection('XLEAK')) {
$restype[] = 'XLEAK';
- $info = ' XLEAK REASON: ' . rtrim($section_text['XLEAK']);
+ $info = ' XLEAK REASON: ' . rtrim($test->getSection('XLEAK'));
} else {
$restype[] = 'FAIL';
}
@@ -3431,6 +3321,10 @@ function show_result(
}
+class BorkageException extends Exception
+{
+}
+
class JUnit
{
private bool $enabled = true;
@@ -3843,6 +3737,206 @@ class RuntestsValgrind
}
}
+class TestFile
+{
+ private string $fileName;
+
+ private array $sections = ['TEST' => ''];
+
+ private const ALLOWED_SECTIONS = [
+ 'EXPECT', 'EXPECTF', 'EXPECTREGEX', 'EXPECTREGEX_EXTERNAL', 'EXPECT_EXTERNAL', 'EXPECTF_EXTERNAL', 'EXPECTHEADERS',
+ 'POST', 'POST_RAW', 'GZIP_POST', 'DEFLATE_POST', 'PUT', 'GET', 'COOKIE', 'ARGS',
+ 'FILE', 'FILEEOF', 'FILE_EXTERNAL', 'REDIRECTTEST',
+ 'CAPTURE_STDIO', 'STDIN', 'CGI', 'PHPDBG',
+ 'INI', 'ENV', 'EXTENSIONS',
+ 'SKIPIF', 'XFAIL', 'XLEAK', 'CLEAN',
+ 'CREDITS', 'DESCRIPTION', 'CONFLICTS', 'WHITESPACE_SENSITIVE',
+ ];
+
+ public function __construct(string $fileName, bool $inRedirect)
+ {
+ $this->fileName = $fileName;
+
+ $this->readFile();
+ $this->validateAndProcess($inRedirect);
+ }
+
+ public function hasSection(string $name): bool
+ {
+ return isset($this->sections[$name]);
+ }
+
+ public function hasAllSections(string ...$names): bool
+ {
+ foreach ($names as $section) {
+ if (!isset($this->sections[$section])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public function hasAnySections(string ...$names): bool
+ {
+ foreach ($names as $section) {
+ if (isset($this->sections[$section])) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function sectionNotEmpty(string $name): bool
+ {
+ return !empty($this->sections[$name]);
+ }
+
+ public function getSection(string $name): string
+ {
+ if (!isset($this->sections[$name])) {
+ throw new Exception("Section $name not found");
+ }
+ return $this->sections[$name];
+ }
+
+ public function getName(): string
+ {
+ return trim($this->getSection('TEST'));
+ }
+
+ public function isCGI(): bool
+ {
+ return $this->sectionNotEmpty('CGI')
+ || $this->sectionNotEmpty('GET')
+ || $this->sectionNotEmpty('POST')
+ || $this->sectionNotEmpty('GZIP_POST')
+ || $this->sectionNotEmpty('DEFLATE_POST')
+ || $this->sectionNotEmpty('POST_RAW')
+ || $this->sectionNotEmpty('PUT')
+ || $this->sectionNotEmpty('COOKIE')
+ || $this->sectionNotEmpty('EXPECTHEADERS');
+ }
+
+ /**
+ * TODO Refactor to make it not needed
+ */
+ public function setSection(string $name, string $value): void
+ {
+ $this->sections[$name] = $value;
+ }
+
+ /**
+ * Load the sections of the test file
+ */
+ private function readFile(): void
+ {
+ $fp = fopen($this->fileName, "rb") or error("Cannot open test file: {$this->fileName}");
+
+ if (!feof($fp)) {
+ $line = fgets($fp);
+
+ if ($line === false) {
+ throw new BorkageException("cannot read test");
+ }
+ } else {
+ throw new BorkageException("empty test [{$this->fileName}]");
+ }
+ if (strncmp('--TEST--', $line, 8)) {
+ throw new BorkageException("tests must start with --TEST-- [{$this->fileName}]");
+ }
+
+ $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 = (string) $r[1];
+
+ if (isset($this->sections[$section]) && $this->sections[$section]) {
+ throw new BorkageException("duplicated $section section");
+ }
+
+ // check for unknown sections
+ if (!in_array($section, self::ALLOWED_SECTIONS)) {
+ throw new BorkageException('Unknown section "' . $section . '"');
+ }
+
+ $this->sections[$section] = '';
+ $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL';
+ $secdone = false;
+ continue;
+ }
+
+ // Add to the section text.
+ if (!$secdone) {
+ $this->sections[$section] .= $line;
+ }
+
+ // End of actual test?
+ if ($secfile && preg_match('/^===DONE===\s*$/', $line)) {
+ $secdone = true;
+ }
+ }
+
+ fclose($fp);
+ }
+
+ private function validateAndProcess(bool $inRedirect): void
+ {
+ // the redirect section allows a set of tests to be reused outside of
+ // a given test dir
+ if ($this->hasSection('REDIRECTTEST')) {
+ if ($inRedirect) {
+ throw new BorkageException("Can't redirect a test from within a redirected test");
+ }
+ return;
+ }
+ if (!$this->hasSection('PHPDBG') && $this->hasSection('FILE') + $this->hasSection('FILEEOF') + $this->hasSection('FILE_EXTERNAL') != 1) {
+ throw new BorkageException("missing section --FILE--");
+ }
+
+ if ($this->hasSection('FILEEOF')) {
+ $this->sections['FILE'] = preg_replace("/[\r\n]+$/", '', $this->sections['FILEEOF']);
+ unset($this->sections['FILEEOF']);
+ }
+
+ foreach (['FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX'] as $prefix) {
+ // For grepping: FILE_EXTERNAL, EXPECT_EXTERNAL, EXPECTF_EXTERNAL, EXPECTREGEX_EXTERNAL
+ $key = $prefix . '_EXTERNAL';
+
+ if ($this->hasSection($key)) {
+ // don't allow tests to retrieve files from anywhere but this subdirectory
+ $dir = dirname($this->fileName);
+ $fileName = $dir . '/' . trim(str_replace('..', '', $this->getSection($key)));
+
+ if (file_exists($fileName)) {
+ $this->sections[$prefix] = file_get_contents($fileName);
+ } else {
+ throw new BorkageException("could not load --" . $key . "-- " . $dir . '/' . trim($fileName));
+ }
+ }
+ }
+
+ if (($this->hasSection('EXPECT') + $this->hasSection('EXPECTF') + $this->hasSection('EXPECTREGEX')) != 1) {
+ throw new BorkageException("missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--");
+ }
+
+ if ($this->hasSection('PHPDBG') && !$this->hasSection('STDIN')) {
+ $this->sections['STDIN'] = $this->sections['PHPDBG'] . "\n";
+ }
+ }
+}
+
function init_output_buffers(): void
{
// Delete as much output buffers as possible.