Bearsampp 2026.9.23
Loading...
Searching...
No Matches
RunTest.php
Go to the documentation of this file.
1<?php
16
20require_once 'PEAR.php';
21require_once 'PEAR/Config.php';
22
23define('DETAILED', 1);
24putenv("PHP_PEAR_RUNTESTS=1");
25
45{
46 var $_headers = array();
49 var $_php;
59 var $ini_overwrites = array(
60 'output_handler=',
61 'open_basedir=',
62 'disable_functions=',
63 'output_buffering=Off',
64 'display_errors=1',
65 'log_errors=0',
66 'html_errors=0',
67 'report_zend_debug=0',
68 'docref_root=',
69 'docref_ext=.html',
70 'error_prepend_string=',
71 'error_append_string=',
72 'auto_prepend_file=',
73 'auto_append_file=',
74 'xdebug.default_enable=0',
75 'allow_url_fopen=1',
76 );
77
82 function __construct($logger = null, $options = array())
83 {
84 if (!defined('E_DEPRECATED')) {
85 define('E_DEPRECATED', 0);
86 }
87 if (!defined('E_STRICT')) {
88 define('E_STRICT', 0);
89 }
90 $excluded_error_reporting = E_DEPRECATED;
91 if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 80400) {
92 $excluded_error_reporting |= E_STRICT;
93 }
94 $this->ini_overwrites[] = 'error_reporting=' . (E_ALL & ~$excluded_error_reporting);
95 if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 80500) {
96 $this->ini_overwrites[] = 'report_memleaks=0';
97 }
98 if (is_null($logger)) {
99 require_once 'PEAR/Common.php';
100 $logger = new PEAR_Common;
101 }
102 $this->_logger = $logger;
103 $this->_options = $options;
104
105 $conf = &PEAR_Config::singleton();
106 $this->_php = $conf->get('php_bin');
107 }
108
117 function system_with_timeout($commandline, $env = null, $stdin = null)
118 {
119 $data = '';
120 $proc = proc_open($commandline, array(
121 0 => array('pipe', 'r'),
122 1 => array('pipe', 'w'),
123 2 => array('pipe', 'w')
124 ), $pipes, null, $env, array('suppress_errors' => true));
125
126 if (!$proc) {
127 return false;
128 }
129
130 if (is_string($stdin)) {
131 fwrite($pipes[0], $stdin);
132 }
133 fclose($pipes[0]);
134
135 while (true) {
136 /* hide errors from interrupted syscalls */
137 $r = $pipes;
138 unset($r[0]);
139 $e = $w = [];
140 $n = @stream_select($r, $w, $e, 60);
141
142 if ($n === 0) {
143 /* timed out */
144 $data .= "\n ** ERROR: process timed out **\n";
145 proc_terminate($proc);
146 return array(1234567890, $data);
147 } else if ($n > 0) {
148 $line = fread($pipes[1], 8192);
149 if (strlen($line) == 0) {
150 /* EOF */
151 break;
152 }
153 $data .= $line;
154 }
155 }
156 if (function_exists('proc_get_status')) {
157 $stat = proc_get_status($proc);
158 if ($stat['signaled']) {
159 $data .= "\nTermsig=".$stat['stopsig'];
160 }
161 }
162 $code = proc_close($proc);
163 if (function_exists('proc_get_status')) {
164 $code = $stat['exitcode'];
165 }
166 return array($code, $data);
167 }
168
184 function iniString2array($ini_string)
185 {
186 if (!$ini_string) {
187 return array();
188 }
189 $split = preg_split('/[\s]|=/', $ini_string, -1, PREG_SPLIT_NO_EMPTY);
190 $key = $split[1][0] == '"' ? substr($split[1], 1) : $split[1];
191 $value = $split[2][strlen($split[2]) - 1] == '"' ? substr($split[2], 0, -1) : $split[2];
192 // FIXME review if this is really the struct to go with
193 $array = array($key => array('operator' => $split[0], 'value' => $value));
194 return $array;
195 }
196
197 function settings2array($settings, $ini_settings)
198 {
199 foreach ($settings as $setting) {
200 if (strpos($setting, '=') !== false) {
201 $setting = explode('=', $setting, 2);
202 $name = trim(strtolower($setting[0]));
203 $value = trim($setting[1]);
204 $ini_settings[$name] = $value;
205 }
206 }
207 return $ini_settings;
208 }
209
210 function settings2params($ini_settings)
211 {
212 $settings = '';
213 foreach ($ini_settings as $name => $value) {
214 if (is_array($value)) {
215 $operator = $value['operator'];
216 $value = $value['value'];
217 } else {
218 $operator = '-d';
219 }
220 $value = addslashes($value);
221 $settings .= " $operator \"$name=$value\"";
222 }
223 return $settings;
224 }
225
226 function _preparePhpBin($php, $file, $ini_settings)
227 {
228 $file = escapeshellarg($file);
229 $cmd = $php . $ini_settings . ' -f ' . $file;
230
231 return $cmd;
232 }
233
234 function runPHPUnit($file, $ini_settings = '')
235 {
236 if (!file_exists($file) && file_exists(getcwd() . DIRECTORY_SEPARATOR . $file)) {
237 $file = realpath(getcwd() . DIRECTORY_SEPARATOR . $file);
238 } elseif (file_exists($file)) {
239 $file = realpath($file);
240 }
241
242 $cmd = $this->_preparePhpBin($this->_php, $file, $ini_settings);
243 if (isset($this->_logger)) {
244 $this->_logger->log(2, 'Running command "' . $cmd . '"');
245 }
246
247 $savedir = getcwd(); // in case the test moves us around
248 chdir(dirname($file));
249 echo `$cmd`;
250 chdir($savedir);
251 return 'PASSED'; // we have no way of knowing this information so assume passing
252 }
253
266 function run($file, $ini_settings = array(), $test_number = 1)
267 {
268 $this->_restorePHPBinary();
269
270 if (empty($this->_options['cgi'])) {
271 // try to see if php-cgi is in the path
272 $res = $this->system_with_timeout('php-cgi -v');
273 if (false !== $res && !(is_array($res) && in_array($res[0], array(-1, 127)))) {
274 $this->_options['cgi'] = 'php-cgi';
275 }
276 }
277 if (1 < $len = strlen($this->tests_count)) {
278 $test_number = str_pad($test_number, $len, ' ', STR_PAD_LEFT);
279 $test_nr = "[$test_number/$this->tests_count] ";
280 } else {
281 $test_nr = '';
282 }
283
284 $file = realpath($file);
285 $section_text = $this->_readFile($file);
286 if (PEAR::isError($section_text)) {
287 return $section_text;
288 }
289
290 if (isset($section_text['POST_RAW']) && isset($section_text['UPLOAD'])) {
291 return PEAR::raiseError("Cannot contain both POST_RAW and UPLOAD in test file: $file");
292 }
293
294 $cwd = getcwd();
295
296 $pass_options = '';
297 if (!empty($this->_options['ini'])) {
298 $pass_options = $this->_options['ini'];
299 }
300
301 if (is_string($ini_settings)) {
302 $ini_settings = $this->iniString2array($ini_settings);
303 }
304
305 $ini_settings = $this->settings2array($this->ini_overwrites, $ini_settings);
306 if ($section_text['INI']) {
307 if (strpos($section_text['INI'], '{PWD}') !== false) {
308 $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
309 }
310 $ini = preg_split( "/[\n\r]+/", $section_text['INI']);
311 $ini_settings = $this->settings2array($ini, $ini_settings);
312 }
313 $ini_settings = $this->settings2params($ini_settings);
314 $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file);
315
316 $tested = trim($section_text['TEST']);
317 $tested.= !isset($this->_options['simple']) ? "[$shortname]" : ' ';
318
319 if (!empty($section_text['POST']) || !empty($section_text['POST_RAW']) ||
320 !empty($section_text['UPLOAD']) || !empty($section_text['GET']) ||
321 !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) {
322 if (empty($this->_options['cgi'])) {
323 if (!isset($this->_options['quiet'])) {
324 $this->_logger->log(0, "SKIP $test_nr$tested (reason: --cgi option needed for this test, type 'pear help run-tests')");
325 }
326 if (isset($this->_options['tapoutput'])) {
327 return array('ok', ' # skip --cgi option needed for this test, "pear help run-tests" for info');
328 }
329 return 'SKIPPED';
330 }
331 $this->_savePHPBinary();
332 $this->_php = $this->_options['cgi'];
333 }
334
335 $temp_dir = realpath(dirname($file));
336 $main_file_name = basename($file, 'phpt');
337 $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff';
338 $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log';
339 $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp';
340 $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out';
341 $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem';
342 $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php';
343 $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php';
344 $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php';
345 $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.');
346
347 // unlink old test results
348 $this->_cleanupOldFiles($file);
349
350 // Check if test should be skipped.
351 $res = $this->_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings);
352 if ($res == 'SKIPPED' || count($res) != 2) {
353 return $res;
354 }
355 $info = $res['info'];
356 $warn = $res['warn'];
357
358 // We've satisfied the preconditions - run the test!
359 if (isset($this->_options['coverage']) && $this->xdebug_loaded) {
360 $xdebug_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'xdebug';
361 $text = "\n" . 'function coverage_shutdown() {' .
362 "\n" . ' $xdebug = var_export(xdebug_get_code_coverage(), true);';
363 if (!function_exists('file_put_contents')) {
364 $text .= "\n" . ' $fh = fopen(\'' . $xdebug_file . '\', "wb");' .
365 "\n" . ' if ($fh !== false) {' .
366 "\n" . ' fwrite($fh, $xdebug);' .
367 "\n" . ' fclose($fh);' .
368 "\n" . ' }';
369 } else {
370 $text .= "\n" . ' file_put_contents(\'' . $xdebug_file . '\', $xdebug);';
371 }
372
373 // Workaround for http://pear.php.net/bugs/bug.php?id=17292
374 $lines = explode("\n", $section_text['FILE']);
375 $numLines = count($lines);
376 $namespace = '';
377 $coverage_shutdown = 'coverage_shutdown';
378
379 if (
380 substr($lines[0], 0, 2) == '<?' ||
381 substr($lines[0], 0, 5) == '<?php'
382 ) {
383 unset($lines[0]);
384 }
385
386
387 for ($i = 0; $i < $numLines; $i++) {
388 if (isset($lines[$i]) && substr($lines[$i], 0, 9) == 'namespace') {
389 $namespace = substr($lines[$i], 10, -1);
390 $coverage_shutdown = $namespace . '\\coverage_shutdown';
391 $namespace = "namespace " . $namespace . ";\n";
392
393 unset($lines[$i]);
394 break;
395 }
396 }
397
398 $text .= "\n xdebug_stop_code_coverage();" .
399 "\n" . '} // end coverage_shutdown()' .
400 "\n\n" . 'register_shutdown_function("' . $coverage_shutdown . '");';
401 $text .= "\n" . 'xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);' . "\n";
402
403 $this->save_text($temp_file, "<?php\n" . $namespace . $text . "\n" . implode("\n", $lines));
404 } else {
405 $this->save_text($temp_file, $section_text['FILE']);
406 }
407
408 $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : '';
409 $cmd = $this->_preparePhpBin($this->_php, $temp_file, $ini_settings);
410 $cmd.= "$args 2>&1";
411 if (isset($this->_logger)) {
412 $this->_logger->log(2, 'Running command "' . $cmd . '"');
413 }
414
415 // Reset environment from any previous test.
416 $env = $this->_resetEnv($section_text, $temp_file);
417
418 $section_text = $this->_processUpload($section_text, $file);
419 if (PEAR::isError($section_text)) {
420 return $section_text;
421 }
422
423 if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
424 $post = trim($section_text['POST_RAW']);
425 $raw_lines = explode("\n", $post);
426
427 $request = '';
428 $started = false;
429 foreach ($raw_lines as $i => $line) {
430 if (empty($env['CONTENT_TYPE']) &&
431 preg_match('/^Content-Type:(.*)/i', $line, $res)) {
432 $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
433 continue;
434 }
435 if ($started) {
436 $request .= "\n";
437 }
438 $started = true;
439 $request .= $line;
440 }
441
442 $env['CONTENT_LENGTH'] = strlen($request);
443 $env['REQUEST_METHOD'] = 'POST';
444
445 $this->save_text($tmp_post, $request);
446 $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post";
447 } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
448 $post = trim($section_text['POST']);
449 $this->save_text($tmp_post, $post);
450 $content_length = strlen($post);
451
452 $env['REQUEST_METHOD'] = 'POST';
453 $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
454 $env['CONTENT_LENGTH'] = $content_length;
455
456 $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post";
457 } else {
458 $env['REQUEST_METHOD'] = 'GET';
459 $env['CONTENT_TYPE'] = '';
460 $env['CONTENT_LENGTH'] = '';
461 }
462
463 if (OS_WINDOWS && isset($section_text['RETURNS'])) {
464 ob_start();
465 system($cmd, $return_value);
466 $out = ob_get_contents();
467 ob_end_clean();
468 $section_text['RETURNS'] = (int) trim($section_text['RETURNS']);
469 $returnfail = ($return_value != $section_text['RETURNS']);
470 } else {
471 $returnfail = false;
472 $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null;
473 $out = $this->system_with_timeout($cmd, $env, $stdin);
474 $return_value = $out[0];
475 $out = $out[1];
476 }
477
478 $output = preg_replace('/\r\n/', "\n", trim($out));
479
480 if (isset($tmp_post) && realpath($tmp_post) && file_exists($tmp_post)) {
481 @unlink(realpath($tmp_post));
482 }
483 chdir($cwd); // in case the test moves us around
484
485 /* when using CGI, strip the headers from the output */
486 $output = $this->_stripHeadersCGI($output);
487
488 if (isset($section_text['EXPECTHEADERS'])) {
489 $testheaders = $this->_processHeaders($section_text['EXPECTHEADERS']);
490 $missing = array_diff_assoc($testheaders, $this->_headers);
491 $changed = '';
492 foreach ($missing as $header => $value) {
493 if (isset($this->_headers[$header])) {
494 $changed .= "-$header: $value\n+$header: ";
495 $changed .= $this->_headers[$header];
496 } else {
497 $changed .= "-$header: $value\n";
498 }
499 }
500 if ($missing) {
501 // tack on failed headers to output:
502 $output .= "\n====EXPECTHEADERS FAILURE====:\n$changed";
503 }
504 }
505
506 $this->_testCleanup($section_text, $temp_clean);
507
508 // Does the output match what is expected?
509 do {
510 if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
511 if (isset($section_text['EXPECTF'])) {
512 $wanted = trim($section_text['EXPECTF']);
513 } else {
514 $wanted = trim($section_text['EXPECTREGEX']);
515 }
516 $wanted_re = preg_replace('/\r\n/', "\n", $wanted);
517 if (isset($section_text['EXPECTF'])) {
518 $wanted_re = preg_quote($wanted_re, '/');
519 // Stick to basics
520 $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy
521 $wanted_re = str_replace("%S", ".*?", $wanted_re); //not greedy
522 $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re);
523 $wanted_re = str_replace("%d", "[0-9]+", $wanted_re);
524 $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re);
525 $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re);
526 $wanted_re = str_replace("%c", ".", $wanted_re);
527 // %f allows two points "-.0.0" but that is the best *simple* expression
528 }
529
530 /* DEBUG YOUR REGEX HERE
531 var_dump($wanted_re);
532 print(str_repeat('=', 80) . "\n");
533 var_dump($output);
534 */
535 if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) {
536 if (file_exists($temp_file)) {
537 unlink($temp_file);
538 }
539 if (array_key_exists('FAIL', $section_text)) {
540 break;
541 }
542 if (!isset($this->_options['quiet'])) {
543 $this->_logger->log(0, "PASS $test_nr$tested$info");
544 }
545 if (isset($this->_options['tapoutput'])) {
546 return array('ok', ' - ' . $tested);
547 }
548 return 'PASSED';
549 }
550 } else {
551 if (isset($section_text['EXPECTFILE'])) {
552 $f = $temp_dir . '/' . trim($section_text['EXPECTFILE']);
553 if (!($fp = @fopen($f, 'rb'))) {
554 return PEAR::raiseError('--EXPECTFILE-- section file ' .
555 $f . ' not found');
556 }
557 fclose($fp);
558 $section_text['EXPECT'] = file_get_contents($f);
559 }
560
561 if (isset($section_text['EXPECT'])) {
562 $wanted = preg_replace('/\r\n/', "\n", trim($section_text['EXPECT']));
563 } else {
564 $wanted = '';
565 }
566
567 // compare and leave on success
568 if (!$returnfail && 0 == strcmp($output, $wanted)) {
569 if (file_exists($temp_file)) {
570 unlink($temp_file);
571 }
572 if (array_key_exists('FAIL', $section_text)) {
573 break;
574 }
575 if (!isset($this->_options['quiet'])) {
576 $this->_logger->log(0, "PASS $test_nr$tested$info");
577 }
578 if (isset($this->_options['tapoutput'])) {
579 return array('ok', ' - ' . $tested);
580 }
581 return 'PASSED';
582 }
583 }
584 } while (false);
585
586 if (array_key_exists('FAIL', $section_text)) {
587 // we expect a particular failure
588 // this is only used for testing PEAR_RunTest
589 $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null;
590 $faildiff = $this->generate_diff($wanted, $output, null, $expectf);
591 $faildiff = preg_replace('/\r/', '', $faildiff);
592 $wanted = preg_replace('/\r/', '', trim($section_text['FAIL']));
593 if ($faildiff == $wanted) {
594 if (!isset($this->_options['quiet'])) {
595 $this->_logger->log(0, "PASS $test_nr$tested$info");
596 }
597 if (isset($this->_options['tapoutput'])) {
598 return array('ok', ' - ' . $tested);
599 }
600 return 'PASSED';
601 }
602 unset($section_text['EXPECTF']);
603 $output = $faildiff;
604 if (isset($section_text['RETURNS'])) {
605 return PEAR::raiseError('Cannot have both RETURNS and FAIL in the same test: ' .
606 $file);
607 }
608 }
609
610 // Test failed so we need to report details.
611 $txt = $warn ? 'WARN ' : 'FAIL ';
612 $this->_logger->log(0, $txt . $test_nr . $tested . $info);
613
614 // write .exp
615 $res = $this->_writeLog($exp_filename, $wanted);
616 if (PEAR::isError($res)) {
617 return $res;
618 }
619
620 // write .out
621 $res = $this->_writeLog($output_filename, $output);
622 if (PEAR::isError($res)) {
623 return $res;
624 }
625
626 // write .diff
627 $returns = isset($section_text['RETURNS']) ?
628 array(trim($section_text['RETURNS']), $return_value) : null;
629 $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null;
630 $data = $this->generate_diff($wanted, $output, $returns, $expectf);
631 $res = $this->_writeLog($diff_filename, $data);
632 if (isset($this->_options['showdiff'])) {
633 $this->_logger->log(0, "========DIFF========");
634 $this->_logger->log(0, $data);
635 $this->_logger->log(0, "========DONE========");
636 }
637 if (PEAR::isError($res)) {
638 return $res;
639 }
640
641 // write .log
642 $data = "
643---- EXPECTED OUTPUT
644$wanted
645---- ACTUAL OUTPUT
646$output
647---- FAILED
648";
649
650 if ($returnfail) {
651 $data .= "
652---- EXPECTED RETURN
653$section_text[RETURNS]
654---- ACTUAL RETURN
655$return_value
656";
657 }
658
659 $res = $this->_writeLog($log_filename, $data);
660 if (PEAR::isError($res)) {
661 return $res;
662 }
663
664 if (isset($this->_options['tapoutput'])) {
665 $wanted = explode("\n", $wanted);
666 $wanted = "# Expected output:\n#\n#" . implode("\n#", $wanted);
667 $output = explode("\n", $output);
668 $output = "#\n#\n# Actual output:\n#\n#" . implode("\n#", $output);
669 return array($wanted . $output . 'not ok', ' - ' . $tested);
670 }
671 return $warn ? 'WARNED' : 'FAILED';
672 }
673
674 function generate_diff($wanted, $output, $rvalue, $wanted_re)
675 {
676 $w = explode("\n", $wanted);
677 $o = explode("\n", $output);
678 $wr = explode("\n", $wanted_re);
679 $w1 = array_diff_assoc($w, $o);
680 $o1 = array_diff_assoc($o, $w);
681 $o2 = $w2 = array();
682 foreach ($w1 as $idx => $val) {
683 if (!$wanted_re || !isset($wr[$idx]) || !isset($o1[$idx]) ||
684 !preg_match('/^' . $wr[$idx] . '\\z/', $o1[$idx])) {
685 $w2[sprintf("%03d<", $idx)] = sprintf("%03d- ", $idx + 1) . $val;
686 }
687 }
688 foreach ($o1 as $idx => $val) {
689 if (!$wanted_re || !isset($wr[$idx]) ||
690 !preg_match('/^' . $wr[$idx] . '\\z/', $val)) {
691 $o2[sprintf("%03d>", $idx)] = sprintf("%03d+ ", $idx + 1) . $val;
692 }
693 }
694 $diff = array_merge($w2, $o2);
695 ksort($diff);
696 $extra = $rvalue ? "##EXPECTED: $rvalue[0]\r\n##RETURNED: $rvalue[1]" : '';
697 return implode("\r\n", $diff) . $extra;
698 }
699
700 // Write the given text to a temporary file, and return the filename.
701 function save_text($filename, $text)
702 {
703 if (!$fp = fopen($filename, 'w')) {
704 return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)");
705 }
706 fwrite($fp, $text);
707 fclose($fp);
708 if (1 < DETAILED) echo "
709FILE $filename {{{
710$text
711}}}
712";
713 }
714
715 function _cleanupOldFiles($file)
716 {
717 $temp_dir = realpath(dirname($file));
718 $mainFileName = basename($file, 'phpt');
719 $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'diff';
720 $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'log';
721 $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'exp';
722 $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'out';
723 $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'mem';
724 $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'php';
725 $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'skip.php';
726 $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'clean.php';
727 $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.');
728
729 // unlink old test results
730 @unlink($diff_filename);
731 @unlink($log_filename);
732 @unlink($exp_filename);
733 @unlink($output_filename);
734 @unlink($memcheck_filename);
735 @unlink($temp_file);
736 @unlink($temp_skipif);
737 @unlink($tmp_post);
738 @unlink($temp_clean);
739 }
740
741 function _runSkipIf($section_text, $temp_skipif, $tested, $ini_settings)
742 {
743 $info = '';
744 $warn = false;
745 if (array_key_exists('SKIPIF', $section_text) && trim($section_text['SKIPIF'])) {
746 $this->save_text($temp_skipif, $section_text['SKIPIF']);
747 $output = $this->system_with_timeout("$this->_php$ini_settings -f \"$temp_skipif\"");
748 $output = $output[1];
749 $loutput = ltrim($output);
750 unlink($temp_skipif);
751 if (!strncasecmp('skip', $loutput, 4)) {
752 $skipreason = "SKIP $tested";
753 if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) {
754 $skipreason .= '(reason: ' . $m[1] . ')';
755 }
756 if (!isset($this->_options['quiet'])) {
757 $this->_logger->log(0, $skipreason);
758 }
759 if (isset($this->_options['tapoutput'])) {
760 return array('ok', ' # skip ' . $reason);
761 }
762 return 'SKIPPED';
763 }
764
765 if (!strncasecmp('info', $loutput, 4)
766 && preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) {
767 $info = " (info: $m[1])";
768 }
769
770 if (!strncasecmp('warn', $loutput, 4)
771 && preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) {
772 $warn = true; /* only if there is a reason */
773 $info = " (warn: $m[1])";
774 }
775 }
776
777 return array('warn' => $warn, 'info' => $info);
778 }
779
780 function _stripHeadersCGI($output)
781 {
782 $this->headers = array();
783 if (!empty($this->_options['cgi']) &&
784 $this->_php == $this->_options['cgi'] &&
785 preg_match("/^(.*?)(?:\n\n(.*)|\\z)/s", $output, $match)) {
786 $output = isset($match[2]) ? trim($match[2]) : '';
787 $this->_headers = $this->_processHeaders($match[1]);
788 }
789
790 return $output;
791 }
792
798 function _processHeaders($text)
799 {
800 $headers = array();
801 $rh = preg_split("/[\n\r]+/", $text);
802 foreach ($rh as $line) {
803 if (strpos($line, ':')!== false) {
804 $line = explode(':', $line, 2);
805 $headers[trim($line[0])] = trim($line[1]);
806 }
807 }
808 return $headers;
809 }
810
811 function _readFile($file)
812 {
813 // Load the sections of the test file.
814 $section_text = array(
815 'TEST' => '(unnamed test)',
816 'SKIPIF' => '',
817 'GET' => '',
818 'COOKIE' => '',
819 'POST' => '',
820 'ARGS' => '',
821 'INI' => '',
822 'CLEAN' => '',
823 );
824
825 if (!is_file($file) || !$fp = fopen($file, "r")) {
826 return PEAR::raiseError("Cannot open test file: $file");
827 }
828
829 $section = '';
830 while (!feof($fp)) {
831 $line = fgets($fp);
832
833 // Match the beginning of a section.
834 if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
835 $section = $r[1];
836 $section_text[$section] = '';
837 continue;
838 } elseif (empty($section)) {
839 fclose($fp);
840 return PEAR::raiseError("Invalid sections formats in test file: $file");
841 }
842
843 // Add to the section text.
844 $section_text[$section] .= $line;
845 }
846 fclose($fp);
847
848 return $section_text;
849 }
850
851 function _writeLog($logname, $data)
852 {
853 if (!$log = fopen($logname, 'w')) {
854 return PEAR::raiseError("Cannot create test log - $logname");
855 }
856 fwrite($log, $data);
857 fclose($log);
858 }
859
860 function _resetEnv($section_text, $temp_file)
861 {
862 $env = $_ENV;
863 $env['REDIRECT_STATUS'] = '';
864 $env['QUERY_STRING'] = '';
865 $env['PATH_TRANSLATED'] = '';
866 $env['SCRIPT_FILENAME'] = '';
867 $env['REQUEST_METHOD'] = '';
868 $env['CONTENT_TYPE'] = '';
869 $env['CONTENT_LENGTH'] = '';
870 if (!empty($section_text['ENV'])) {
871 if (strpos($section_text['ENV'], '{PWD}') !== false) {
872 $section_text['ENV'] = str_replace('{PWD}', dirname($temp_file), $section_text['ENV']);
873 }
874 foreach (explode("\n", trim($section_text['ENV'])) as $e) {
875 $e = explode('=', trim($e), 2);
876 if (!empty($e[0]) && isset($e[1])) {
877 $env[$e[0]] = $e[1];
878 }
879 }
880 }
881 if (array_key_exists('GET', $section_text)) {
882 $env['QUERY_STRING'] = trim($section_text['GET']);
883 } else {
884 $env['QUERY_STRING'] = '';
885 }
886 if (array_key_exists('COOKIE', $section_text)) {
887 $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
888 } else {
889 $env['HTTP_COOKIE'] = '';
890 }
891 $env['REDIRECT_STATUS'] = '1';
892 $env['PATH_TRANSLATED'] = $temp_file;
893 $env['SCRIPT_FILENAME'] = $temp_file;
894
895 return $env;
896 }
897
898 function _processUpload($section_text, $file)
899 {
900 if (array_key_exists('UPLOAD', $section_text) && !empty($section_text['UPLOAD'])) {
901 $upload_files = trim($section_text['UPLOAD']);
902 $upload_files = explode("\n", $upload_files);
903
904 $request = "Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737\n" .
905 "-----------------------------20896060251896012921717172737\n";
906 foreach ($upload_files as $fileinfo) {
907 $fileinfo = explode('=', $fileinfo);
908 if (count($fileinfo) != 2) {
909 return PEAR::raiseError("Invalid UPLOAD section in test file: $file");
910 }
911 if (!realpath(dirname($file) . '/' . $fileinfo[1])) {
912 return PEAR::raiseError("File for upload does not exist: $fileinfo[1] " .
913 "in test file: $file");
914 }
915 $file_contents = file_get_contents(dirname($file) . '/' . $fileinfo[1]);
916 $fileinfo[1] = basename($fileinfo[1]);
917 $request .= "Content-Disposition: form-data; name=\"$fileinfo[0]\"; filename=\"$fileinfo[1]\"\n";
918 $request .= "Content-Type: text/plain\n\n";
919 $request .= $file_contents . "\n" .
920 "-----------------------------20896060251896012921717172737\n";
921 }
922
923 if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
924 // encode POST raw
925 $post = trim($section_text['POST']);
926 $post = explode('&', $post);
927 foreach ($post as $i => $post_info) {
928 $post_info = explode('=', $post_info);
929 if (count($post_info) != 2) {
930 return PEAR::raiseError("Invalid POST data in test file: $file");
931 }
932 $post_info[0] = rawurldecode($post_info[0]);
933 $post_info[1] = rawurldecode($post_info[1]);
934 $post[$i] = $post_info;
935 }
936 foreach ($post as $post_info) {
937 $request .= "Content-Disposition: form-data; name=\"$post_info[0]\"\n\n";
938 $request .= $post_info[1] . "\n" .
939 "-----------------------------20896060251896012921717172737\n";
940 }
941 unset($section_text['POST']);
942 }
943 $section_text['POST_RAW'] = $request;
944 }
945
946 return $section_text;
947 }
948
949 function _testCleanup($section_text, $temp_clean)
950 {
951 if ($section_text['CLEAN']) {
952 $this->_restorePHPBinary();
953
954 // perform test cleanup
955 $this->save_text($temp_clean, $section_text['CLEAN']);
956 $output = $this->system_with_timeout("$this->_php $temp_clean 2>&1");
957 if (strlen($output[1])) {
958 echo "BORKED --CLEAN-- section! output:\n", $output[1];
959 }
960 if (file_exists($temp_clean)) {
961 unlink($temp_clean);
962 }
963 }
964 }
965
966 function _savePHPBinary()
967 {
968 $this->_savephp = $this->_php;
969 }
970
972 {
973 if (isset($this->_savephp))
974 {
975 $this->_php = $this->_savephp;
976 unset($this->_savephp);
977 }
978 }
979}
_restorePHPBinary()
Definition RunTest.php:971
_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings)
Definition RunTest.php:741
_writeLog($logname, $data)
Definition RunTest.php:851
_processHeaders($text)
Definition RunTest.php:798
generate_diff($wanted, $output, $rvalue, $wanted_re)
Definition RunTest.php:674
_resetEnv($section_text, $temp_file)
Definition RunTest.php:860
save_text($filename, $text)
Definition RunTest.php:701
_cleanupOldFiles($file)
Definition RunTest.php:715
_savePHPBinary()
Definition RunTest.php:966
_stripHeadersCGI($output)
Definition RunTest.php:780
const DETAILED
Definition RunTest.php:23
_processUpload($section_text, $file)
Definition RunTest.php:898
_testCleanup($section_text, $temp_clean)
Definition RunTest.php:949
_readFile($file)
Definition RunTest.php:811
$proc
Definition ajax.php:130
__construct($logger=null, $options=array())
Definition RunTest.php:82
system_with_timeout($commandline, $env=null, $stdin=null)
Definition RunTest.php:117
settings2params($ini_settings)
Definition RunTest.php:210
settings2array($settings, $ini_settings)
Definition RunTest.php:197
run($file, $ini_settings=array(), $test_number=1)
Definition RunTest.php:266
iniString2array($ini_string)
Definition RunTest.php:184
_preparePhpBin($php, $file, $ini_settings)
Definition RunTest.php:226
runPHPUnit($file, $ini_settings='')
Definition RunTest.php:234
$options
Definition pearcmd.php:145