Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

more refactoring of test suite

  • Loading branch information...
commit 7cdd71a85f86dcfe22e2276d3919a6ff3ee21eeb 1 parent 1e23d77
@gwoo gwoo authored
View
2  libraries/lithium/action/Request.php
@@ -133,6 +133,7 @@ protected function _init() {
$envs = array('isapi' => 'IIS', 'cgi' => 'CGI', 'cgi-fcgi' => 'CGI');
$this->_env['PLATFORM'] = isset($envs[PHP_SAPI]) ? $envs[PHP_SAPI] : null;
$this->_base = $this->_base ?: $this->_base();
+ $this->query = isset($_GET) ? $_GET : array();
$this->data = isset($_POST) ? $_POST : array();
if (isset($this->data['_method'])) {
@@ -144,7 +145,6 @@ protected function _init() {
$this->_env['REQUEST_METHOD'] = $this->_env['HTTP_X_HTTP_METHOD_OVERRIDE'];
}
-
if (isset($_FILES)) {
$result = array();
$normalize = function($key, $value) use ($result, &$normalize){
View
19 libraries/lithium/core/Libraries.php
@@ -435,21 +435,26 @@ protected static function _locateDeferred($defer, $paths, $params, $options = ar
continue;
}
- foreach ($paths as $pathTemplate => $options) {
+ foreach ($paths as $pathTemplate => $pathOptions) {
if (is_int($pathTemplate)) {
- $pathTemplate = $options;
- $options = array();
+ $pathTemplate = $pathOptions;
+ $pathOptions = array();
}
+ $options += $pathOptions;
+
$scope = isset($options['libraries']) ? (array)$options['libraries'] : null;
if ($scope && !in_array($library, $scope)) {
continue;
}
$params['library'] = $library;
- $classPath = str_replace('\\*', '', String::insert($pathTemplate, $params));
-
- if (file_exists(Libraries::path($classPath))) {
- return $classPath;
+ $class = str_replace('\\*', '', String::insert($pathTemplate, $params));
+ $file = Libraries::path($class, $options);
+ if (file_exists($file)) {
+ if (isset($options['format']) && $options['format'] == 'file') {
+ return $file;
+ }
+ return $class;
}
}
}
View
29 libraries/lithium/test/Controller.php
@@ -10,15 +10,38 @@
use \lithium\test\Reporter;
use \lithium\test\Dispatcher;
+use \lithium\core\Libraries;
+/**
+ * Controller for reporting test results in html
+ *
+ */
class Controller extends \lithium\core\Object {
-
+
+ /**
+ * undocumented function
+ *
+ * @param string $request
+ * @param string $params
+ * @param string $options
+ * @return void
+ */
public function __invoke($request, $params, $options = array()) {
error_reporting(E_ALL | E_STRICT | E_DEPRECATED);
- return Reporter::run(
- Dispatcher::process(Dispatcher::run(null, $params['args'])),
+ $report = Reporter::run(
+ Dispatcher::run(null, $request->query),
array('format' => 'html')
);
+ $filters = Libraries::locate('test.filters');
+ $classes = Libraries::locate('tests', null, array(
+ 'filter' => '/cases|integration|functional/'
+ ));
+ $menu = Reporter::menu($classes, array('format' => 'html', 'tree' => true));
+
+ $template = Libraries::locate('test.reporter.templates', 'layout', array(
+ 'filter' => false, 'format' => 'file', 'suffix' => '.html.php',
+ ));
+ include($template);
}
}
View
121 libraries/lithium/test/Dispatcher.php
@@ -27,7 +27,8 @@ class Dispatcher extends \lithium\core\StaticObject {
* class.
*/
protected static $_classes = array(
- 'group' => '\lithium\test\Group'
+ 'group' => '\lithium\test\Group',
+ 'report' => '\lithium\test\Report'
);
/**
@@ -37,122 +38,26 @@ class Dispatcher extends \lithium\core\StaticObject {
* @param string $group If set, this test group is run. If not set, a group test may
* also be run by passing the 'group' option to the $options parameter.
* @param array $options Options array for the test run. Valid options are:
- * - 'base': Base path of where test cases are located.
- * If not set, the value for 'path' is taken.
* - 'case': The fully namespaced test case to be run.
* - 'group': The fully namespaced test group to be run.
* - 'filters': An array of filters that the test output should be run through.
- * - 'path': Where the test cases are located.
- * Defaults to LITHIUM_LIBRARY_PATH . '/lithium/tests/cases'
* @return array A compactified array of the title, an array of the results, as well
* as an additional array of the restults after the $options['filters']
* have been applied.
*/
public static function run($group = null, $options = array()) {
$defaults = array(
- 'base' => null,
'case' => null,
'group' => null,
'filters' => array(),
- 'path' => LITHIUM_LIBRARY_PATH . '/lithium/tests/cases',
+ 'reporter' => 'html'
);
$options += $defaults;
- if (is_null($options['base'])) {
- $options['base'] = $options['path'];
- }
- $group = $group ?: static::_group($options);
-
- if (!$group) {
- return null;
- }
- $title = $options['case'] ?: $options['group'];
- list($results, $filters) = static::_execute($group, Set::normalize($options['filters']));
-
-
- return compact('title', 'results', 'filters');
- }
-
- /**
- * Generates the sidebar menu on the test summary page.
- *
- * @param string $type The format that the generated output should have.
- * Valid options are 'html' and 'txt'.
- * @return string Formatted menu
- */
- public static function menu($type) {
- $classes = Libraries::locate('tests', null, array(
- 'filter' => '/cases|integration|functional/'
- ));
- $data = array();
-
- $assign = function(&$data, $class, $i = 0) use (&$assign) {
- isset($data[$class[$i]]) ?: $data[] = $class[$i];
- $end = (count($class) <= $i + 1);
-
- if (!$end && ($offset = array_search($class[$i], $data)) !== false) {
- $data[$class[$i]] = array();
- unset($data[$offset]);
- }
- ksort($data);
- $end ?: $assign($data[$class[$i]], $class, $i + 1);
- };
-
- foreach ($classes as $class) {
- $assign($data, explode('\\', str_replace('\tests', '', $class)));
- }
- ksort($data);
-
- $format = function($test) use ($type) {
- if ($type == 'html') {
- if ($test == 'group') {
- return '<li><a href="?group=%1$s">%2$s</a>%3$s</li>';
- }
- if ($test == 'case') {
- return '<li><a href="?case=%2$s\%1$s">%1$s</a></li>';
- }
- }
-
- if ($type == 'txt') {
- if ($test == 'group') {
- return "-group %1$s\n%2$s\n";
- }
- if ($test == 'case') {
- return "-case %1$s\n";
- }
- }
-
- if ($type == 'html') {
- return sprintf('<ul>%s</ul>', $test);
- }
- if ($type == 'txt') {
- return sprintf("\n%s\n", $test);
- }
- };
- $result = null;
-
- $menu = function ($data, $parent = null) use (&$menu, $format, $result) {
- foreach ($data as $key => $row) {
- if (is_array($row) && is_string($key)) {
- $key = strtolower($key);
- $next = $parent . '\\' . $key;
- $result .= sprintf(
- $format('group'), $next, $key, $menu($row, $next)
- );
- } else {
- $next = $parent . '\\' . $key;
- $result .= sprintf($format('case'), $row, $parent);
- }
- }
- return $format($result);
- };
- foreach ($data as $library => $tests) {
- $group = "\\{$library}\\tests";
- $result .= $format(sprintf(
- $format('group'), $group, $library, $menu($tests, $group)
- ));
- }
- return $result;
+ $options['title'] = $options['case'] ?: $options['group'];
+ $options['filters'] = Set::normalize($options['filters']);
+ $report = static::_report($options);
+ return $report;
}
/**
@@ -197,7 +102,7 @@ public static function process($results) {
}
/**
- * Creates the test group class based on either the passed test case or the
+ * Creates the test report class based on either the passed test case or the
* passed test group.
*
* @param array $options Options array passed from Dispatcher::run(). Should contain
@@ -205,12 +110,16 @@ public static function process($results) {
* @return object Group object constructed with the test case or group passed in $options.
* @see \lithium\test\Dispatcher::$_classes
*/
- protected static function _group($options) {
+ protected static function _report($options) {
if (!empty($options['case'])) {
- return new static::$_classes['group'](array('items' => array(new $options['case'])));
+ $items = array(new $options['case']);
} elseif (isset($options['group'])) {
- return new static::$_classes['group'](array('items' => (array)$options['group']));
+ $items = (array)$options['group'];
}
+
+ $group = new static::$_classes['group'](compact('items'));
+ $report = new static::$_classes['report'](compact('group') + $options);
+ return $report;
}
/**
View
125 libraries/lithium/test/Report.php
@@ -8,6 +8,13 @@
namespace lithium\test;
+use \lithium\util\Inflector;
+
+/**
+ * Report object for running group tests holding results
+ *
+ * @package default
+ */
class Report extends \lithium\core\Object {
/**
@@ -26,27 +33,123 @@ class Report extends \lithium\core\Object {
*/
public $filters = array();
- protected $_startTime = null;
+ /**
+ * Title of the group being run
+ *
+ * @var string
+ */
+ public $title = null;
+
+ /**
+ * group and filter results
+ *
+ * @var array
+ */
+ public $results = array('group' => array(), 'filters' => array());
+
+ /**
+ * start and end timers
+ *
+ * @var array
+ */
+ public $timer = array('start' => null, 'end' => null);
+
+ /**
+ * Construct Report Object
+ *
+ * @param array $config Options array for the test run. Valid options are:
+ * - 'case': The fully namespaced test case to be run.
+ * - 'group': The fully namespaced test group to be run.
+ * - 'filters': An array of filters that the test output should be run through.
+ */
+ public function __construct($config = array()) {
+ $defaults = array(
+ 'case' => null,
+ 'group' => null,
+ 'filters' => array(),
+ );
+ parent::__construct((array) $config + $defaults);
+ }
+ /**
+ * undocumented function
+ *
+ * @return void
+ */
protected function _init() {
- $this->_startTime = microtime(true);
+ $this->timer['start'] = microtime(true);
+ $this->group = $this->_config['group'];
+ $this->filters = $this->_config['filters'];
+ $this->title = $this->_config['title'] ?: $this->_config['title'];
+ $this->run();
+ $this->timer['end'] = microtime(true);
}
-
- protected function create($group) {
- $tests = $group->tests();
- $filterResults = array();
- foreach ($filters as $filter => $options) {
+ /**
+ * undocumented function
+ *
+ * @return void
+ */
+ public function run() {
+ $tests = $this->group->tests();
+ foreach ($this->filters as $filter => $options) {
$options = isset($options['apply']) ? $options['apply'] : array();
$tests = $filter::apply($tests, $options);
}
- $results = $tests->run();
+ $this->results['group'] = $tests->run();
- foreach ($filters as $filter => $options) {
+ foreach ($this->filters as $filter => $options) {
$options = isset($options['analyze']) ? $options['analyze'] : array();
- $filterResults[$filter] = $filter::analyze($results, $options);
+ $this->results['filters'][$filter] = $filter::analyze($this->results['group'], $options);
}
- return array($results, $filterResults);
+ }
+
+ /**
+ * undocumented function
+ *
+ * @return void
+ */
+ public function stats() {
+ $results = (array)$this->results['group'];
+ return $this->reporter->stats(array_reduce($results, function($stats, $result) {
+ $stats = (array)$stats + array(
+ 'asserts' => 0,
+ 'passes' => array(),
+ 'fails' => array(),
+ 'exceptions' => array(),
+ 'errors' => array()
+ );
+ $result = empty($result[0]) ? array($result) : $result;
+
+ foreach ($result as $response) {
+ if (empty($response['result'])) {
+ continue;
+ }
+ $result = $response['result'];
+
+ if (in_array($result, array('fail', 'exception'))) {
+ $stats['errors'][] = $response;
+ }
+ unset($response['file'], $response['result']);
+
+ if (in_array($result, array('pass', 'fail'))) {
+ $stats['asserts']++;
+ }
+ if (in_array($result, array('pass', 'fail', 'exception'))) {
+ $stats[Inflector::pluralize($result)][] = $response;
+ }
+ }
+ return $stats;
+ }));
+ }
+
+ /**
+ * undocumented function
+ *
+ * @return void
+ */
+ public function filters() {
+ return $this->reporter->filters((array) $this->results['filters']);
}
}
View
51 libraries/lithium/test/Reporter.php
@@ -8,6 +8,7 @@
namespace lithium\test;
+use \Exception;
use \lithium\core\Libraries;
use \lithium\util\Inflector;
@@ -16,7 +17,7 @@
*
* @param class \lithium\test\Report
*/
-class Reporter extends \lithium\core\Object {
+class Reporter extends \lithium\core\StaticObject {
/**
* undocumented function
@@ -28,13 +29,8 @@ class Reporter extends \lithium\core\Object {
public static function run($report, $options = array()) {
$defaults = array('format' => 'text');
$options += $defaults;
- $reporter = Libraries::locate('test.reporter', Inflector::camelize($options['format']));
- $reporter = new $reporter();
- $classes = Libraries::locate('tests', null, array(
- 'filter' => '/cases|integration|functional/'
- ));
- $menu = static::menu($classes);
- return $reporter->render(compact('report', 'menu', 'classes'));
+ $report->reporter = static::_reporter($options['format']);
+ return $report;
}
/**
@@ -42,12 +38,13 @@ public static function run($report, $options = array()) {
*
* @params array options
* - format: type of reporter class. eg: html default: text
- * - recursive: if true organizes and renders as hierarchy
+ * - tree: true to convert classes to tree structure
*/
public static function menu($classes, $options = array()) {
- $defaults = array('format' => 'text', 'recursive' => false);
+ $defaults = array('format' => 'text', 'tree' => false);
$options += $defaults;
- if ($options['recursive']) {
+
+ if ($options['tree']) {
$data = array();
$assign = function(&$data, $class, $i = 0) use (&$assign) {
isset($data[$class[$i]]) ?: $data[] = $class[$i];
@@ -69,42 +66,56 @@ public static function menu($classes, $options = array()) {
ksort($classes);
$result = null;
- $reporter = Libraries::locate('test.reporter', Inflector::camelize($options['format']));
- $reporter = new $reporter();
+ $reporter = static::_reporter($options['format']);
- if ($options['recursive']) {
+ if ($options['tree']) {
$menu = function ($data, $parent = null) use (&$menu, &$reporter, $result) {
foreach ($data as $key => $row) {
if (is_array($row) && is_string($key)) {
$key = strtolower($key);
$next = $parent . '\\' . $key;
- $result .= $reporter->format('group', array(
+ $result .= $reporter->menu('group', array(
'namespace' => $next, 'name' => $key, 'menu' => $menu($row, $next)
));
} else {
$next = $parent . '\\' . $key;
- $result .= $reporter->format('case', array(
+ $result .= $reporter->menu('case', array(
'namespace' => $parent, 'name' => $row,
));
}
}
- return $format($result);
+ return $reporter->menu(null, array('menu' => $result));
};
foreach ($classes as $library => $tests) {
$group = "\\{$library}\\tests";
- $result .= $report->format(null, array('menu' => $report->format('group', array(
+ $result .= $reporter->menu(null, array('menu' => $reporter->menu('group', array(
'namespace' => $group, 'name' => $library, 'menu' => $menu($tests, $group)
))));
}
return $result;
}
+
foreach ($classes as $test) {
$parts = explode('\\', $test);
$name = array_pop($parts);
$namespace = join('\\', $parts);
- $result .= $reporter->format('case', compact('namespace', 'name'));
+ $result .= $reporter->menu('case', compact('namespace', 'name'));
+ }
+ return $reporter->menu(null, array('menu' => $result));
+ }
+
+ /**
+ * undocumented function
+ *
+ * @param string $format
+ * @return void
+ */
+ protected static function _reporter($format) {
+ $reporter = Libraries::locate('test.reporter', Inflector::camelize($format));
+ if (!$reporter) {
+ throw new Exception("{$format} is not a valid reporter");
}
- return $reporter->format(null, array('menu' => $result));
+ return new $reporter();
}
}
View
85 libraries/lithium/test/reporter/Html.php
@@ -10,13 +10,90 @@
use lithium\util\String;
+/**
+ * Html Reporter
+ *
+ */
class Html extends \lithium\core\Object {
+
+ /**
+ * undocumented function
+ *
+ * @param object $report \lithium\test\Report
+ * @return void
+ */
+ public function stats($stats) {
+ $passes = count($stats['passes']);
+ $fails = count($stats['fails']);
+ $errors = count($stats['errors']);
+ $exceptions = count($stats['exceptions']);
+ $success = ($passes === $stats['asserts'] && $errors === 0);
- public function render($results) {
- $filters = Libraries::locate('test.filters');
- }
+ $result = array(
+ '<div class="test-result test-result-' . ($success ? 'success' : 'fail') . '">',
+ "{$passes} / {$stats['asserts']} passes, {$fails} ",
+ ((intval($stats['fails']) == 1) ? 'fail' : 'fails') . " and {$exceptions} ",
+ ((intval($exceptions) == 1) ? 'exceptions' : 'exceptions'),
+ '</div>'
+ );
- public function format($type, $params = array()) {
+ foreach ((array)$stats['errors'] as $error) {
+ switch ($error['result']) {
+ case 'fail':
+ $error += array('class' => 'unknown', 'method' => 'unknown');
+ $fail = array(
+ '<div class="test-assert test-assert-failed">',
+ "Assertion '{$error['assertion']}' failed in ",
+ "{$error['class']}::{$error['method']}() on line ",
+ "{$error['line']}: ",
+ "<span class=\"content\">{$error['message']}</span>",
+ '</div>'
+ );
+ $result[] = join("\n", $fail);
+ break;
+ case 'exception':
+ $exception = array(
+ '<div class="test-exception">',
+ "Exception thrown in {$error['class']}::{$error['method']}() ",
+ "on line {$error['line']}: ",
+ "<span class=\"content\">{$error['message']}</span>",
+ );
+ if (isset($error['trace']) && !empty($error['trace'])) {
+ $exception[] = "Trace:<span class=\"trace\">{$error['trace']}</span>";
+ }
+ $exception[] = '</div>';
+ $result[] = join("\n", $exception);
+ break;
+ }
+ }
+ return join("\n", $result);
+ }
+
+ /**
+ * undocumented function
+ *
+ * @param string $filters
+ * @return void
+ */
+ public function filters($filters) {
+ $result = array();
+ foreach ((array)$filters as $class => $data) {
+ $result[] = $class::output('html', $data);
+ }
+ return join("\n", $result);
+ }
+
+ /**
+ * Renders a menu item
+ *
+ * @param string $type group, case or null
+ * @param string $params
+ * - namespace
+ * - name
+ * - menu
+ * @return void
+ */
+ public function menu($type, $params = array()) {
$defaults = array(
'namespace' => null, 'name' => null, 'menu' => null
);
View
25 libraries/lithium/test/reporter/templates/layout.html.php
@@ -1,8 +1,13 @@
+<?php
+ use \lithium\util\Inflector;
+ // /var_dump($request);
+
+?>
<!doctype html>
<html>
<head>
<title>Lithium Unit Test Dashboard</title>
- <link rel="stylesheet" href="css/debug.css" />
+ <link rel="stylesheet" href="<?php echo $request->env('base')?>/css/debug.css" />
</head>
<body class="test-dashboard">
<h1>Lithium Unit Test Dashboard</h1>
@@ -13,27 +18,27 @@
</div>
<div style="float:left; padding: 10px; width: 75%">
- <h2>Stats for <?php echo $title; ?></h2>
+ <h2>Stats for <?php echo $report->title; ?></h2>
<h3>Test results</h3>
-
+
<span class="filters">
<?php
- $base = $_SERVER['REQUEST_URI'];
-
foreach ($filters as $i => $class) {
- $url = $base . "&amp;filters[]={$class}";
+ $url = $request->env('REQUEST_URI') . "&amp;filters[]={$class}";
$name = join('', array_slice(explode("\\", $class), -1));
$key = Inflector::underscore($name);
echo "<a class=\"{$key}\" href=\"{$url}\">{$name}</a>";
-
- if ($i < count($filters) - 1) {
- echo ' | ';
- }
+ echo ' | ';
}
?>
</span>
+
+ <?php echo $report->stats(); ?>
+
+ <?php echo $report->filters();?>
+
</div>
<div style="clear:both"></div>
</body>
View
1  libraries/lithium/util/Collection.php
@@ -26,7 +26,6 @@ class Collection extends \lithium\core\Object implements \ArrayAccess, \Iterator
protected $_valid = false;
protected $_classes = array(
- 'record' => '\lithium\model\Record',
'media' => '\lithium\http\Media'
);
Please sign in to comment.
Something went wrong with that request. Please try again.