diff options
author | Bharat Mediratta <bharat@menalto.com> | 2008-12-15 08:52:32 +0000 |
---|---|---|
committer | Bharat Mediratta <bharat@menalto.com> | 2008-12-15 08:52:32 +0000 |
commit | 628058b4ed5aefb543ceb6ca9d3b87828c66bef1 (patch) | |
tree | 89e47f00d008957e75d00e8a5fd04fa67198dea3 /modules/unit_test | |
parent | 31759cb3b3090c1b9d68ac54f2d2622584003563 (diff) |
Refresh from kohana svn trunk r3771
Diffstat (limited to 'modules/unit_test')
-rw-r--r-- | modules/unit_test/config/unit_test.php | 15 | ||||
-rw-r--r-- | modules/unit_test/controllers/unit_test.php | 22 | ||||
-rw-r--r-- | modules/unit_test/libraries/Unit_Test.php | 480 | ||||
-rw-r--r-- | modules/unit_test/views/kohana_unit_test.php | 170 |
4 files changed, 687 insertions, 0 deletions
diff --git a/modules/unit_test/config/unit_test.php b/modules/unit_test/config/unit_test.php new file mode 100644 index 00000000..7f803f22 --- /dev/null +++ b/modules/unit_test/config/unit_test.php @@ -0,0 +1,15 @@ +<?php defined('SYSPATH') OR die('No direct access allowed.'); +/** + * @package Unit_Test + * + * Default paths to scan for tests. + */ +$config['paths'] = array +( + MODPATH.'unit_test/tests', +); + +/** + * Set to TRUE if you want to hide passed tests from the report. + */ +$config['hide_passed'] = FALSE; diff --git a/modules/unit_test/controllers/unit_test.php b/modules/unit_test/controllers/unit_test.php new file mode 100644 index 00000000..1c73e619 --- /dev/null +++ b/modules/unit_test/controllers/unit_test.php @@ -0,0 +1,22 @@ +<?php defined('SYSPATH') OR die('No direct access allowed.'); +/** + * Unit_Test controller. + * + * $Id$ + * + * @package Unit_Test + * @author Kohana Team + * @copyright (c) 2007-2008 Kohana Team + * @license http://kohanaphp.com/license.html + */ +class Unit_test_Controller extends Controller { + + const ALLOW_PRODUCTION = FALSE; + + public function index() + { + // Run tests and show results! + echo new Unit_Test; + } + +}
\ No newline at end of file diff --git a/modules/unit_test/libraries/Unit_Test.php b/modules/unit_test/libraries/Unit_Test.php new file mode 100644 index 00000000..e6010d3c --- /dev/null +++ b/modules/unit_test/libraries/Unit_Test.php @@ -0,0 +1,480 @@ +<?php defined('SYSPATH') OR die('No direct access allowed.'); +/** + * Unit_Test library. + * + * $Id$ + * + * @package Unit_Test + * @author Kohana Team + * @copyright (c) 2007-2008 Kohana Team + * @license http://kohanaphp.com/license.html + */ +class Unit_Test_Core { + + // The path(s) to recursively scan for tests + protected $paths = array(); + + // The results of all tests from every test class + protected $results = array(); + + // Statistics for every test class + protected $stats = array(); + + /** + * Sets the test path(s), runs the tests inside and stores the results. + * + * @param string(s) test path(s) + * @return void + */ + public function __construct() + { + // Merge possible default test path(s) from config with the rest + $paths = array_merge(func_get_args(), Kohana::config('unit_test.paths', FALSE, FALSE)); + + // Normalize all test paths + foreach ($paths as $path) + { + $path = str_replace('\\', '/', realpath((string) $path)); + } + + // Take out duplicate test paths after normalization + $this->paths = array_unique($paths); + + // Loop over each given test path + foreach ($this->paths as $path) + { + // Validate test path + if ( ! is_dir($path)) + throw new Kohana_Exception('unit_test.invalid_test_path', $path); + + // Recursively iterate over each file in the test path + foreach + ( + new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME)) + as $path => $file + ) + { + // Normalize path + $path = str_replace('\\', '/', $path); + + // Skip files without "_Test" suffix + if ( ! $file->isFile() OR substr($path, -9) !== '_Test'.EXT) + continue; + + // The class name should be the same as the file name + $class = substr($path, strrpos($path, '/') + 1, -(strlen(EXT))); + + // Skip hidden files + if (substr($class, 0, 1) === '.') + continue; + + // Check for duplicate test class name + if (class_exists($class, FALSE)) + throw new Kohana_Exception('unit_test.duplicate_test_class', $class, $path); + + // Include the test class + include_once $path; + + // Check whether the test class has been found and loaded + if ( ! class_exists($class, FALSE)) + throw new Kohana_Exception('unit_test.test_class_not_found', $class, $path); + + // Reverse-engineer Test class + $reflector = new ReflectionClass($class); + + // Test classes must extend Unit_Test_Case + if ( ! $reflector->isSubclassOf(new ReflectionClass('Unit_Test_Case'))) + throw new Kohana_Exception('unit_test.test_class_extends', $class); + + // Skip disabled Tests + if ($reflector->getConstant('DISABLED') === TRUE) + continue; + + // Initialize setup and teardown method triggers + $setup = $teardown = FALSE; + + // Look for valid setup and teardown methods + foreach (array('setup', 'teardown') as $method_name) + { + if ($reflector->hasMethod($method_name)) + { + $method = new ReflectionMethod($class, $method_name); + $$method_name = ($method->isPublic() AND ! $method->isStatic() AND $method->getNumberOfRequiredParameters() === 0); + } + } + + // Initialize test class results and stats + $this->results[$class] = array(); + $this->stats[$class] = array + ( + 'passed' => 0, + 'failed' => 0, + 'errors' => 0, + 'total' => 0, + 'score' => 0, + ); + + // Loop through all the class methods + foreach ($reflector->getMethods() as $method) + { + // Skip invalid test methods + if ( ! $method->isPublic() OR $method->isStatic() OR $method->getNumberOfRequiredParameters() !== 0) + continue; + + // Test methods should be suffixed with "_test" + if (substr($method_name = $method->getName(), -5) !== '_test') + continue; + + // Instantiate Test class + $object = new $class; + + try + { + // Run setup method + if ($setup === TRUE) + { + $object->setup(); + } + + // Run the actual test + $object->$method_name(); + + // Run teardown method + if ($teardown === TRUE) + { + $object->teardown(); + } + + $this->stats[$class]['total']++; + + // Test passed + $this->results[$class][$method_name] = TRUE; + $this->stats[$class]['passed']++; + + } + catch (Kohana_Unit_Test_Exception $e) + { + $this->stats[$class]['total']++; + // Test failed + $this->results[$class][$method_name] = $e; + $this->stats[$class]['failed']++; + } + catch (Exception $e) + { + $this->stats[$class]['total']++; + + // Test error + $this->results[$class][$method_name] = $e; + $this->stats[$class]['errors']++; + } + + // Calculate score + $this->stats[$class]['score'] = $this->stats[$class]['passed'] * 100 / $this->stats[$class]['total']; + + // Cleanup + unset($object); + } + } + } + } + + /** + * Generates nice test results. + * + * @param boolean hide passed tests from the report + * @return string rendered test results html + */ + public function report($hide_passed = NULL) + { + // No tests found + if (empty($this->results)) + return Kohana::lang('unit_test.no_tests_found'); + + // Hide passed tests from the report? + $hide_passed = (bool) (($hide_passed !== NULL) ? $hide_passed : Kohana::config('unit_test.hide_passed', FALSE, FALSE)); + + // Render unit_test report + return View::factory('kohana_unit_test') + ->set('results', $this->results) + ->set('stats', $this->stats) + ->set('hide_passed', $hide_passed) + ->render(); + } + + /** + * Magically convert this object to a string. + * + * @return string test report + */ + public function __toString() + { + return $this->report(); + } + + /** + * Magically gets a Unit_Test property. + * + * @param string property name + * @return mixed variable value if the property is found + * @return void if the property is not found + */ + public function __get($key) + { + if (isset($this->$key)) + return $this->$key; + } + +} // End Unit_Test_Core + + +abstract class Unit_Test_Case { + + public function assert_true($value, $debug = NULL) + { + if ($value != TRUE) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_true', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_true_strict($value, $debug = NULL) + { + if ($value !== TRUE) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_true_strict', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_false($value, $debug = NULL) + { + if ($value != FALSE) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_false', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_false_strict($value, $debug = NULL) + { + if ($value !== FALSE) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_false_strict', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_equal($expected, $actual, $debug = NULL) + { + if ($expected != $actual) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_equal', gettype($expected), var_export($expected, TRUE), gettype($actual), var_export($actual, TRUE)), $debug); + + return $this; + } + + public function assert_not_equal($expected, $actual, $debug = NULL) + { + if ($expected == $actual) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_equal', gettype($expected), var_export($expected, TRUE), gettype($actual), var_export($actual, TRUE)), $debug); + + return $this; + } + + public function assert_same($expected, $actual, $debug = NULL) + { + if ($expected !== $actual) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_same', gettype($expected), var_export($expected, TRUE), gettype($actual), var_export($actual, TRUE)), $debug); + + return $this; + } + + public function assert_not_same($expected, $actual, $debug = NULL) + { + if ($expected === $actual) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_same', gettype($expected), var_export($expected, TRUE), gettype($actual), var_export($actual, TRUE)), $debug); + + return $this; + } + + public function assert_boolean($value, $debug = NULL) + { + if ( ! is_bool($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_boolean', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_not_boolean($value, $debug = NULL) + { + if (is_bool($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_boolean', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_integer($value, $debug = NULL) + { + if ( ! is_int($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_integer', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_not_integer($value, $debug = NULL) + { + if (is_int($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_integer', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_float($value, $debug = NULL) + { + if ( ! is_float($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_float', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_not_float($value, $debug = NULL) + { + if (is_float($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_float', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_array($value, $debug = NULL) + { + if ( ! is_array($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_array', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_array_key($key, $array, $debug = NULL) + { + if ( ! array_key_exists($key, $array)) { + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_array_key', gettype($key), var_export($key, TRUE)), $debug); + } + + return $this; + } + + public function assert_in_array($value, $array, $debug = NULL) + { + if ( ! in_array($value, $array)) { + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_in_array', gettype($value), var_export($value, TRUE)), $debug); + } + + return $this; + } + + public function assert_not_array($value, $debug = NULL) + { + if (is_array($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_array', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_object($value, $debug = NULL) + { + if ( ! is_object($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_object', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_not_object($value, $debug = NULL) + { + if (is_object($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_object', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_null($value, $debug = NULL) + { + if ($value !== NULL) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_null', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_not_null($value, $debug = NULL) + { + if ($value === NULL) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_null', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_empty($value, $debug = NULL) + { + if ( ! empty($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_empty', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_not_empty($value, $debug = NULL) + { + if (empty($value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_empty', gettype($value), var_export($value, TRUE)), $debug); + + return $this; + } + + public function assert_pattern($value, $regex, $debug = NULL) + { + if ( ! is_string($value) OR ! is_string($regex) OR ! preg_match($regex, $value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_pattern', var_export($value, TRUE), var_export($regex, TRUE)), $debug); + + return $this; + } + + public function assert_not_pattern($value, $regex, $debug = NULL) + { + if ( ! is_string($value) OR ! is_string($regex) OR preg_match($regex, $value)) + throw new Kohana_Unit_Test_Exception(Kohana::lang('unit_test.assert_not_pattern', var_export($value, TRUE), var_export($regex, TRUE)), $debug); + + return $this; + } + +} // End Unit_Test_Case + + +class Kohana_Unit_Test_Exception extends Exception { + + protected $debug = NULL; + + /** + * Sets exception message and debug info. + * + * @param string message + * @param mixed debug info + * @return void + */ + public function __construct($message, $debug = NULL) + { + // Failure message + parent::__construct((string) $message); + + // Extra user-defined debug info + $this->debug = $debug; + + // Overwrite failure location + $trace = $this->getTrace(); + $this->file = $trace[0]['file']; + $this->line = $trace[0]['line']; + } + + /** + * Returns the user-defined debug info + * + * @return mixed debug property + */ + public function getDebug() + { + return $this->debug; + } + +} // End Kohana_Unit_Test_Exception diff --git a/modules/unit_test/views/kohana_unit_test.php b/modules/unit_test/views/kohana_unit_test.php new file mode 100644 index 00000000..c2a98adc --- /dev/null +++ b/modules/unit_test/views/kohana_unit_test.php @@ -0,0 +1,170 @@ +<?php defined('SYSPATH') OR die('No direct access allowed.'); ?> +<style type="text/css"> +#kohana-unit-test +{ + font-family: Monaco, 'Courier New'; + background-color: #F8FFF8; + margin-top: 20px; + clear: both; + padding: 10px 10px 0; + border: 1px solid #E5EFF8; + text-align: left; +} +#kohana-unit-test pre +{ + margin: 0; + font: inherit; +} +#kohana-unit-test table +{ + font-size: 1.0em; + color: #4D6171; + width: 100%; + border-collapse: collapse; + border-top: 1px solid #E5EFF8; + border-right: 1px solid #E5EFF8; + border-left: 1px solid #E5EFF8; + margin-bottom: 10px; +} +#kohana-unit-test th +{ + text-align: left; + border-bottom: 1px solid #E5EFF8; + background-color: #263038; + padding: 3px; + color: #FFF; +} +#kohana-unit-test td +{ + background-color: #FFF; + border-bottom: 1px solid #E5EFF8; + padding: 3px; +} +#kohana-unit-test .k-stats +{ + font-weight: normal; + color: #83919C; + text-align: right; +} +#kohana-unit-test .k-debug +{ + padding: 3px; + background-color: #FFF0F0; + border: 1px solid #FFD0D0; + border-right-color: #FFFBFB; + border-bottom-color: #FFFBFB; + color: #83919C; +} +#kohana-unit-test .k-altrow td +{ + background-color: #F7FBFF; +} +#kohana-unit-test .k-name +{ + width: 25%; + border-right: 1px solid #E5EFF8; +} +#kohana-unit-test .k-passed +{ + background-color: #E0FFE0; +} +#kohana-unit-test .k-altrow .k-passed +{ + background-color: #D0FFD0; +} +#kohana-unit-test .k-failed +{ + background-color: #FFE0E0; +} +#kohana-unit-test .k-altrow .k-failed +{ + background-color: #FFD0D0; +} +#kohana-unit-test .k-error +{ + background-color: #FFFFE0; +} +#kohana-unit-test .k-altrow .k-error +{ + background-color: #FFFFD1; +} +</style> + +<div id="kohana-unit-test"> + +<?php + +foreach ($results as $class => $methods): +text::alternate(); + +?> + + <table> + <tr> + <th><?php echo $class ?></th> + <th class="k-stats"> + <?php printf('%s: %.2f%%', Kohana::lang('unit_test.score'), $stats[$class]['score']) ?> | + <?php echo Kohana::lang('unit_test.total'), ': ', $stats[$class]['total'] ?>, + <?php echo Kohana::lang('unit_test.passed'), ': ', $stats[$class]['passed'] ?>, + <?php echo Kohana::lang('unit_test.failed'), ': ', $stats[$class]['failed'] ?>, + <?php echo Kohana::lang('unit_test.errors'), ': ', $stats[$class]['errors'] ?> + </th> + </tr> + + <?php if (empty($methods)): ?> + + <tr> + <td colspan="2"><?php echo Kohana::lang('unit_test.no_tests_found') ?></td> + </tr> + + <?php else: + + foreach ($methods as $method => $result): + + // Hide passed tests from report + if ($result === TRUE AND $hide_passed === TRUE) + continue; + + ?> + + <tr class="<?php echo text::alternate('', 'k-altrow') ?>"> + <td class="k-name"><?php echo $method ?></td> + + <?php if ($result === TRUE): ?> + + <td class="k-passed"><strong><?php echo Kohana::lang('unit_test.passed') ?></strong></td> + + <?php elseif ($result instanceof Kohana_Unit_Test_Exception): ?> + + <td class="k-failed"> + <strong><?php echo Kohana::lang('unit_test.failed') ?></strong> + <pre><?php echo html::specialchars($result->getMessage()) ?></pre> + <?php echo html::specialchars($result->getFile()) ?> (<?php echo Kohana::lang('unit_test.line') ?> <?php echo $result->getLine() ?>) + + <?php if ($result->getDebug() !== NULL): ?> + <pre class="k-debug" title="Debug info"><?php echo '(', gettype($result->getDebug()), ') ', html::specialchars(var_export($result->getDebug(), TRUE)) ?></pre> + <?php endif ?> + + </td> + + <?php elseif ($result instanceof Exception): ?> + + <td class="k-error"> + <strong><?php echo Kohana::lang('unit_test.error') ?></strong> + <pre><?php echo html::specialchars($result->getMessage()) ?></pre> + <?php echo html::specialchars($result->getFile()) ?> (<?php echo Kohana::lang('unit_test.line') ?> <?php echo $result->getLine() ?>) + </td> + + <?php endif ?> + + </tr> + + <?php endforeach ?> + + <?php endif ?> + + </table> + +<?php endforeach ?> + +</div> |