3 changed files with 505 additions and 0 deletions
@ -0,0 +1,7 @@ |
|||
####################################################### |
|||
# name: basic |
|||
# purpose: check basic functionality of phpdbg console |
|||
# expect: TEST::EXACT |
|||
####################################################### |
|||
# [Nothing to execute!] |
|||
####################################################### |
|||
@ -0,0 +1,476 @@ |
|||
<?php |
|||
namespace phpdbg\testing { |
|||
|
|||
/** |
|||
* TestConfigurationExceptions are thrown |
|||
* when the configuration prohibits tests executing |
|||
* |
|||
* @package phpdbg |
|||
* @subpackage testing |
|||
*/ |
|||
class TestConfigurationException extends \Exception { |
|||
|
|||
/** |
|||
* |
|||
* @param array Tests confguration |
|||
* @param message Exception message |
|||
* @param ... formatting parameters |
|||
*/ |
|||
public function __construct() { |
|||
$argv = func_get_args(); |
|||
|
|||
if (count($argv)) { |
|||
|
|||
$this->config = array_shift($argv); |
|||
$this->message = vsprintf( |
|||
array_shift($argv), $argv); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Tests is the console programming API for the test suite |
|||
* |
|||
* @package phpdbg |
|||
* @subpackage testing |
|||
*/ |
|||
class Tests { |
|||
|
|||
/** |
|||
* Construct the console object |
|||
* |
|||
* @param array basic configuration |
|||
* @param array command line |
|||
*/ |
|||
public function __construct(&$config, $cmd) { |
|||
while (($key = array_shift($cmd))) { |
|||
switch (substr($key, 0, 1)) { |
|||
case '-': switch(substr($key, 1, 1)) { |
|||
case '-': { |
|||
$arg = substr($key, 2); |
|||
if (($e=strpos($arg, '=')) !== false) { |
|||
$key = substr($arg, 0, $e); |
|||
$value = substr($arg, $e+1); |
|||
} else { |
|||
$key = $arg; |
|||
$value = array_shift($cmd); |
|||
} |
|||
|
|||
if (isset($key) && isset($value)) { |
|||
switch ($key) { |
|||
case 'phpdbg': |
|||
case 'width': |
|||
$config[$key] = $value; |
|||
break; |
|||
|
|||
default: { |
|||
if (isset($config[$key])) { |
|||
if (is_array($config[$key])) { |
|||
$config[$key][] = $value; |
|||
} else { |
|||
$config[$key] = array($config[$key], $value); |
|||
} |
|||
} else { |
|||
$config[$key] = $value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} break; |
|||
|
|||
default: |
|||
$config['flags'][] = substr($key, 1); |
|||
} break; |
|||
} |
|||
} |
|||
|
|||
if (!is_executable($config['phpdbg'])) { |
|||
throw new TestConfigurationException( |
|||
$config, 'phpdbg could not be found at the specified path (%s)', $config['phpdbg']); |
|||
} else $config['phpdbg'] = realpath($config['phpdbg']); |
|||
|
|||
$conifg['width'] = (integer) $config['width']; |
|||
|
|||
/* display properly, all the time */ |
|||
if ($config['width'] < 50) { |
|||
$config['width'] = 50; |
|||
} |
|||
|
|||
/* calculate column widths */ |
|||
$config['lwidth'] = ceil($config['width'] / 3); |
|||
$config['rwidth'] = ceil($config['width'] - $config['lwidth']) - 5; |
|||
|
|||
$this->config = &$config; |
|||
|
|||
if (in_array('help', $this->config['flags'])|| |
|||
in_array('h', $this->config['flags'])) { |
|||
$this->logUsage(); |
|||
exit; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Find valid paths as specified by configuration |
|||
* |
|||
*/ |
|||
public function findPaths($in = null) { |
|||
$paths = array(); |
|||
$where = ($in != null) ? array($in) : $this->config['path']; |
|||
|
|||
foreach ($where as &$path) { |
|||
if ($path) { |
|||
if (is_dir($path)) { |
|||
$paths[] = $path; |
|||
foreach (scandir($path) as $child) { |
|||
if ($child != '.' && $child != '..') { |
|||
$paths = array_merge( |
|||
$paths, $this->findPaths("$path/$child")); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return $paths; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param string the path to log |
|||
*/ |
|||
public function logPath($path) { |
|||
printf( |
|||
'%s [%s]%s', |
|||
str_repeat( |
|||
'-', $this->config['width'] - strlen($path)), |
|||
$path, PHP_EOL); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param string the path to log |
|||
*/ |
|||
public function logPathStats($path) { |
|||
$total = array_sum($this->stats[$path]); |
|||
|
|||
@$this->totals[true] += $this->stats[$path][true]; |
|||
@$this->totals[false] += $this->stats[$path][false]; |
|||
|
|||
$stats = @sprintf( |
|||
"%d/%d %%%d", |
|||
$this->stats[$path][true], |
|||
$this->stats[$path][false], |
|||
(100 / $total) * $this->stats[$path][true]); |
|||
|
|||
printf( |
|||
'%s [%s]%s', |
|||
str_repeat( |
|||
' ', $this->config['width'] - strlen($stats)), |
|||
$stats, PHP_EOL); |
|||
|
|||
printf("%s%s", str_repeat('-', $this->config['width']+3), PHP_EOL); |
|||
printf("%s", PHP_EOL); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function logStats() { |
|||
$total = array_sum($this->totals); |
|||
$stats = @sprintf( |
|||
"%d/%d %%%d", |
|||
$this->totals[true], |
|||
$this->totals[false], |
|||
(100 / $total) * $this->totals[true]); |
|||
printf( |
|||
'%s [%s]%s', |
|||
str_repeat( |
|||
' ', $this->config['width'] - strlen($stats)), |
|||
$stats, PHP_EOL); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
protected function logUsage() { |
|||
printf('usage: php %s [flags] [options]%s', $this->config['exec'], PHP_EOL); |
|||
printf('[options]:%s', PHP_EOL); |
|||
printf("\t--path\t\tadd a path to scan outside of tests directory%s", PHP_EOL); |
|||
printf("\t--width\t\tset line width%s", PHP_EOL); |
|||
printf("\t--options\toptions to pass to phpdbg%s", PHP_EOL); |
|||
printf("\t--phpdbg\tpath to phpdbg binary%s", PHP_EOL); |
|||
printf('[flags]:%s', PHP_EOL); |
|||
printf("\t-nodiff\t\tdo not write diffs on failure%s", PHP_EOL); |
|||
printf("\t-nolog\t\tdo not write logs on failure%s", PHP_EOL); |
|||
printf('[examples]:%s', PHP_EOL); |
|||
printf("\tphp %s --phpdbg=/usr/local/bin/phpdbg --path=/usr/src/phpdbg/tests --options -n%s", |
|||
$this->config['exec'], PHP_EOL); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Find valid tests at the specified path (assumed valid) |
|||
* |
|||
* @param string a valid path |
|||
*/ |
|||
public function findTests($path) { |
|||
$tests = array(); |
|||
|
|||
foreach (scandir($path) as $file) { |
|||
if ($file == '.' || $file == '..') |
|||
continue; |
|||
|
|||
$test = sprintf('%s/%s', $path, $file); |
|||
|
|||
if (preg_match('~\.test$~', $test)) { |
|||
yield new Test($this->config, $test); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param Test the test to log |
|||
*/ |
|||
public function logTest($path, Test $test) { |
|||
@$this->stats[$path][($result=$test->getResult())]++; |
|||
|
|||
printf( |
|||
"%-{$this->config['lwidth']}s %-{$this->config['rwidth']}s [%s]%s", |
|||
$test->name, |
|||
$test->purpose, |
|||
$result ? "PASS" : "FAIL", |
|||
PHP_EOL); |
|||
} |
|||
|
|||
protected $config; |
|||
} |
|||
|
|||
class Test { |
|||
/* |
|||
* Expect exact line for line match |
|||
*/ |
|||
const EXACT = 0x00000001; |
|||
|
|||
/* |
|||
* Expect strpos() !== false |
|||
*/ |
|||
const STRING = 0x00000010; |
|||
|
|||
/* |
|||
* Expect stripos() !== false |
|||
*/ |
|||
const CISTRING = 0x00000100; |
|||
|
|||
/** |
|||
* Constructs a new Test object given a specilized phpdbginit file |
|||
* |
|||
* @param array configuration |
|||
* @param string file |
|||
*/ |
|||
public function __construct(&$config, &$file) { |
|||
if (($handle = fopen($file, 'r'))) { |
|||
while (($line = fgets($handle))) { |
|||
$trim = trim($line); |
|||
|
|||
switch (substr($trim, 0, 1)) { |
|||
case '#': if (($chunks = array_map('trim', preg_split('~:~', substr($trim, 1), 2)))) { |
|||
if (property_exists($this, $chunks[0])) { |
|||
switch ($chunks[0]) { |
|||
case 'expect': { |
|||
if ($chunks[1]) { |
|||
switch (strtoupper($chunks[1])) { |
|||
case 'TEST::EXACT': |
|||
case 'EXACT': { $this->expect = TEST::EXACT; } break; |
|||
|
|||
case 'TEST::STRING': |
|||
case 'STRING': { $this->expect = TEST::STRING; } break; |
|||
|
|||
case 'TEST::CISTRING': |
|||
case 'CISTRING': { $this->expect = TEST::CISTRING; } break; |
|||
|
|||
default: |
|||
throw new TestConfigurationException( |
|||
$this->config, "unknown type of expectation (%s)", $chunks[1]); |
|||
} |
|||
} |
|||
} break; |
|||
|
|||
default: { |
|||
$this->$chunks[0] = $chunks[1]; |
|||
} |
|||
} |
|||
} else switch(substr($trim, 1, 1)) { |
|||
case '#': { /* do nothing */ } break; |
|||
|
|||
default: { |
|||
$this->match[] = ltrim(substr($trim, 1)); |
|||
} |
|||
} |
|||
} break; |
|||
|
|||
default: |
|||
break 2; |
|||
} |
|||
} |
|||
fclose($handle); |
|||
|
|||
$this->config = &$config; |
|||
$this->file = &$file; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Obvious !! |
|||
* |
|||
*/ |
|||
public function getResult() { |
|||
$options = sprintf( |
|||
'-i%s -rrqb', $this->file); |
|||
|
|||
if ($this->options) { |
|||
$options = sprintf( |
|||
'%s %s %s', |
|||
$options, |
|||
$this->config['options'], |
|||
$this->options |
|||
); |
|||
} else { |
|||
$options = sprintf( |
|||
'%s %s', $options, $this->config['options'] |
|||
); |
|||
} |
|||
|
|||
$result = `{$this->config['phpdbg']} {$options}`; |
|||
|
|||
if ($result) { |
|||
foreach (preg_split('~(\r|\n)~', $result) as $num => $line) { |
|||
if (!$line && !isset($this->match[$num])) |
|||
continue; |
|||
|
|||
switch ($this->expect) { |
|||
case TEST::EXACT: { |
|||
if (strcmp($line, $this->match[$num]) !== 0) { |
|||
$this->diff['wants'][$num] = &$this->match[$num]; |
|||
$this->diff['gets'][$num] = $line; |
|||
} |
|||
} continue 2; |
|||
|
|||
case TEST::STRING: { |
|||
if (strpos($line, $this->match[$num]) === false) { |
|||
$this->diff['wants'][$num] = &$this->match[$num]; |
|||
$this->diff['gets'][$num] = $line; |
|||
} |
|||
} continue 2; |
|||
|
|||
case TEST::CISTRING: { |
|||
if (stripos($line, $this->match[$num]) === false) { |
|||
$this->diff['wants'][$num] = &$this->match[$num]; |
|||
$this->diff['gets'][$num] = $line; |
|||
} |
|||
} continue 2; |
|||
} |
|||
} |
|||
} |
|||
|
|||
$this->writeLog($result); |
|||
$this->writeDiff(); |
|||
|
|||
return (count($this->diff) == 0); |
|||
} |
|||
|
|||
/** |
|||
* Write diff to disk if configuration allows it |
|||
* |
|||
*/ |
|||
protected function writeDiff() { |
|||
$diff = sprintf( |
|||
'%s/%s.diff', |
|||
dirname($this->file), basename($this->file)); |
|||
|
|||
if (count($this->diff['wants'])) { |
|||
if (!in_array('nodiff', $this->config['flags'])) { |
|||
if (($diff = fopen($diff, 'w+'))) { |
|||
|
|||
foreach ($this->diff['wants'] as $line => $want) { |
|||
$got = $this->diff['gets'][$line]; |
|||
|
|||
fprintf( |
|||
$diff, '(%d) -%s%s', $line+1, $want, PHP_EOL); |
|||
fprintf( |
|||
$diff, '(%d) +%s%s', $line+1, $got, PHP_EOL); |
|||
} |
|||
|
|||
fclose($diff); |
|||
} |
|||
} |
|||
} else unlink($diff); |
|||
} |
|||
|
|||
/** |
|||
* Write log to disk if configuration allows it |
|||
* |
|||
*/ |
|||
protected function writeLog(&$result = null) { |
|||
$log = sprintf( |
|||
'%s/%s.log', |
|||
dirname($this->file), basename($this->file)); |
|||
|
|||
if (count($this->diff) && $result) { |
|||
if (!in_array('nolog', $this->config['flags'])) { |
|||
@file_put_contents( |
|||
$log, $result); |
|||
} |
|||
} else unlink($log); |
|||
} |
|||
|
|||
public $name; |
|||
public $purpose; |
|||
public $file; |
|||
public $options; |
|||
public $expect; |
|||
public $match; |
|||
|
|||
protected $diff; |
|||
protected $stats; |
|||
protected $totals; |
|||
} |
|||
} |
|||
|
|||
namespace { |
|||
use \phpdbg\Testing\Test; |
|||
use \phpdbg\Testing\Tests; |
|||
|
|||
$cwd = dirname(__FILE__); |
|||
$cmd = $_SERVER['argv']; |
|||
{ |
|||
$config = array( |
|||
'exec' => realpath(array_shift($cmd)), |
|||
'phpdbg' => realpath(sprintf( |
|||
'%s/../phpdbg', $cwd |
|||
)), |
|||
'path' => array( |
|||
realpath(dirname(__FILE__)) |
|||
), |
|||
'flags' => array(), |
|||
'width' => 75 |
|||
); |
|||
|
|||
$tests = new Tests($config, $cmd); |
|||
|
|||
foreach ($tests->findPaths() as $path) { |
|||
$tests->logPath($path); |
|||
|
|||
foreach ($tests->findTests($path) as $test) { |
|||
$tests->logTest($path, $test); |
|||
} |
|||
|
|||
$tests->logPathStats($path); |
|||
} |
|||
|
|||
$tests->logStats(); |
|||
} |
|||
} |
|||
?>
|
|||
@ -0,0 +1,22 @@ |
|||
################################################# |
|||
# name: set |
|||
# purpose: tests for set commands |
|||
# expect: TEST::CISTRING |
|||
################################################# |
|||
# setting prompt color |
|||
# setting error color |
|||
# setting notice color |
|||
# Failed to find breakpoint #0 |
|||
# oplog disabled |
|||
# not enabled |
|||
# opened oplog test.log |
|||
# nothing |
|||
################################################# |
|||
set color prompt none |
|||
set color error none |
|||
set color notice none |
|||
set prompt promot> |
|||
set break 0 |
|||
set oplog |
|||
set oplog 0 |
|||
set oplog test.log |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue