summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/unit_test/config/unit_test.php15
-rw-r--r--modules/unit_test/controllers/unit_test.php22
-rw-r--r--modules/unit_test/libraries/Unit_Test.php480
-rw-r--r--modules/unit_test/views/kohana_unit_test.php170
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') ?>&nbsp;<?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') ?>&nbsp;<?php echo $result->getLine() ?>)
+ </td>
+
+ <?php endif ?>
+
+ </tr>
+
+ <?php endforeach ?>
+
+ <?php endif ?>
+
+ </table>
+
+<?php endforeach ?>
+
+</div>