Skip to content
Browse files

Refactoring the `Test` command to use typed output handlers, and cons…

…olidating filter output in JSON templating.
  • Loading branch information...
1 parent 9a42990 commit ea0abeb12ffa4d734fb4f60d60b4b45607ede3e7 @nateabele nateabele committed
View
155 libraries/lithium/console/command/Test.php
@@ -46,66 +46,96 @@ class Test extends \lithium\console\Command {
public $format = 'txt';
/**
+ * An array of closures, mapped by type, which are set up to handle different test output
+ * formats.
+ *
+ * @var array
+ */
+ protected $_handlers = array();
+
+ /**
+ * Initializes the output handlers.
+ *
+ * @see lithium\console\command\Test::$_handlers
+ * @return void
+ */
+ protected function _init() {
+ parent::_init();
+ $self = $this;
+ $this->_handlers += array(
+ 'txt' => function($runner, $path) use ($self) {
+ $message = sprintf('Running test(s) in `%s`... ', ltrim($path, '\\'));
+ $self->header('Test');
+ $self->out($message, array('nl' => false));
+
+ $report = $runner();
+ $self->out('done.', 2);
+ $self->out('{:heading}Results{:end}', 0);
+ $self->out($report->render('stats', $report->stats()));
+
+ foreach ($report->filters() as $filter => $options) {
+ $data = $report->results['filters'][$filter];
+ $self->out($report->render($options['name'], compact('data')));
+ }
+
+ $self->hr();
+ $self->nl();
+ return $report;
+ },
+ 'json' => function($runner, $path) use ($self) {
+ $report = $runner();
+
+ if ($results = $report->filters()) {
+ $filters = array();
+
+ foreach ($results as $filter => $options) {
+ $filters[$options['name']] = $report->results['filters'][$filter];
+ }
+ }
+ $self->out($report->render('stats', $report->stats() + compact('filters')));
+ return $report;
+ }
+ );
+ }
+
+ /**
* Runs tests given a path to a directory or file containing tests. The path to the
- * test(s) may be absolte or relative to the current working directory.
+ * test(s) may be absolute or relative to the current working directory.
*
* {{{
- * lithium test lithium/tests/cases/core/ObjectTest.php
- * lithium test lithium/tests/cases/core
+ * li3 test lithium/tests/cases/core/ObjectTest.php
+ * li3 test lithium/tests/cases/core
+ * }}}
+ *
+ * If you are in the working directory of an application or plugin and wish to run all tests,
+ * simply execute the following:
+ *
+ * {{{
+ * li3 test tests/cases
* }}}
*
* @param string $path Absolute or relative path to tests.
* @return boolean Will exit with status `1` if one or more tests failed otherwise with `0`.
*/
public function run($path = null) {
- $path = str_replace('\\', '/', $path);
-
- if (!$path) {
- $this->error('Please provide a path to tests.');
- return false;
- }
- if ($path[0] != '/') {
- $path = $this->request->env('working') . '/' . $path;
- }
- if (!$path = realpath($path)) {
- $this->error('Not a valid path.');
+ if (!$path = $this->_path($path)) {
return false;
}
- $filters = $this->filters ? array_map('trim', explode(',', $this->filters)) : array();
+ $handlers = $this->_handlers;
- if (!$libraryPath = $this->_library($path)) {
- $this->error("No library registered for path `{$path}`.");
+ if (!isset($handlers[$this->format]) || !is_callable($handlers[$this->format])) {
+ $this->error(sprintf('No handler for format `%s`... ', $this->format));
return false;
}
- $path = $libraryPath;
-
- if ($this->format == 'txt') {
- $this->header('Test');
- $this->out(sprintf('Running test(s) in `%s`... ', $path), array('nl' => false));
- }
- error_reporting(E_ALL | E_STRICT | E_DEPRECATED);
+ $filters = $this->filters ? array_map('trim', explode(',', $this->filters)) : array();
+ $params = compact('filters') + array('reporter' => 'console', 'format' => $this->format);
- $report = Dispatcher::run($path, compact('filters') + array(
- 'reporter' => 'console',
- 'format' => $this->format
- ));
+ $runner = function() use ($path, $params) {
+ error_reporting(E_ALL | E_STRICT | E_DEPRECATED);
+ return Dispatcher::run($path, $params);
+ };
+ $report = $handlers[$this->format]($runner, $path);
$stats = $report->stats();
-
- if ($this->format == 'txt') {
- $this->out('done.', 2);
- $this->out('{:heading}Results{:end}', 0);
- }
- $this->out($report->render('stats', $stats));
-
- foreach ($report->filters() as $filter => $options) {
- $data = $report->results['filters'][$filter];
- $this->out($report->render($options['name'], compact('data')));
- }
-
- if ($this->format == 'txt') {
- $this->hr();
- $this->nl();
- }
return $stats['success'];
}
@@ -113,15 +143,44 @@ public function run($path = null) {
* Finds a library for given path.
*
* @param string $path Normalized (to slashes) absolute or relative path.
- * @return string|void The library's path on success.
+ * @return string Returns the library's path on success, or `null` on failure.
*/
protected function _library($path) {
foreach (Libraries::get() as $name => $library) {
- if (strpos($path, $library['path']) === 0) {
- $path = str_replace(array($library['path'], '.php'), null, $path);
- return '\\' . $name . str_replace('/', '\\', $path);
+ if (strpos($path, $library['path']) !== 0) {
+ continue;
}
+ $path = str_replace(array($library['path'], '.php'), null, $path);
+ return '\\' . $name . str_replace('/', '\\', $path);
+ }
+ }
+
+ /**
+ * Validates an absolute or relative path to test cases.
+ *
+ * @param string $path The directory or file path to one or more test cases
+ * @return string Returns a fully-resolved physical path, or `false`, if an error occurs.
+ */
+ protected function _path($path) {
+ $path = str_replace('\\', '/', $path);
+
+ if (!$path) {
+ $this->error('Please provide a path to tests.');
+ return false;
+ }
+ if ($path[0] != '/') {
+ $path = $this->request->env('working') . '/' . $path;
+ }
+ if (!$path = realpath($path)) {
+ $this->error('Not a valid path.');
+ return false;
+ }
+
+ if (!$libraryPath = $this->_library($path)) {
+ $this->error("No library registered for path `{$path}`.");
+ return false;
}
+ return $libraryPath;
}
}
View
6 libraries/lithium/test/Report.php
@@ -218,7 +218,8 @@ function($value) { return is_array($value) ? count($value) : $value; }, $stats
*/
public function render($template, $data = array()) {
$config = $this->_config;
- if ($template == "stats") {
+
+ if ($template == "stats" && !$data) {
$data = $this->stats();
}
$template = Libraries::locate("test.templates.{$config['reporter']}", $template, array(
@@ -235,11 +236,12 @@ public function render($template, $data = array()) {
}
public function filters(array $filters = array()) {
- if (!empty($this->_filters) && empty($filters)) {
+ if ($this->_filters && !$filters) {
return $this->_filters;
}
$filters += (array) $this->_config['filters'];
$results = array();
+
foreach ($filters as $filter => $options) {
if (!$class = Libraries::locate('test.filter', $filter)) {
throw new ClassNotFoundException("`{$class}` is not a valid test filter.");
View
2 libraries/lithium/test/templates/console/stats.json.php
@@ -1 +1 @@
-<?php echo json_encode(compact('count', 'stats')); ?>
+<?php echo json_encode(compact('count', 'stats', 'filters')); ?>

0 comments on commit ea0abeb

Please sign in to comment.
Something went wrong with that request. Please try again.