summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gallery_unit_test/controllers/test.php28
-rw-r--r--modules/gallery_unit_test/views/kohana_unit_test.php58
-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/i18n/en_US/unit_test.php43
-rw-r--r--modules/unit_test/i18n/es_ES/unit_test.php43
-rw-r--r--modules/unit_test/i18n/pt_BR/unit_test.php39
-rw-r--r--modules/unit_test/i18n/ru_RU/unit_test.php43
-rw-r--r--modules/unit_test/libraries/Unit_Test.php480
-rw-r--r--modules/unit_test/tests/Example_Test.php103
-rw-r--r--modules/unit_test/tests/Valid_Helper_Test.php121
-rw-r--r--modules/unit_test/views/kohana_unit_test.php169
12 files changed, 1164 insertions, 0 deletions
diff --git a/modules/gallery_unit_test/controllers/test.php b/modules/gallery_unit_test/controllers/test.php
new file mode 100644
index 00000000..de3a3410
--- /dev/null
+++ b/modules/gallery_unit_test/controllers/test.php
@@ -0,0 +1,28 @@
+<?php
+/*
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2008 Bharat Mediratta
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+class Test_Controller extends Controller {
+ function Index() {
+ if (!defined('TEST_MODE')) {
+ print Kohana::show_404();
+ }
+ $test = new Unit_Test(DOCROOT . "modules/gallery_unit_test/tests");
+ echo $test;
+ }
+}
diff --git a/modules/gallery_unit_test/views/kohana_unit_test.php b/modules/gallery_unit_test/views/kohana_unit_test.php
new file mode 100644
index 00000000..2201245c
--- /dev/null
+++ b/modules/gallery_unit_test/views/kohana_unit_test.php
@@ -0,0 +1,58 @@
+<?php
+foreach ($results as $class => $methods) {
+ echo str_repeat("-", 100), "\n";
+ echo $class, "\n";
+ echo str_repeat("-", 100), "\n";
+
+ foreach (array("score", "total", "passed", "failed", "errors") as $key) {
+ @$totals[$key] += $stats[$class][$key];
+ }
+
+ if (empty($methods)) {
+ echo Kohana::lang("unit_test.no_tests_found"), "\n";
+ } else {
+ foreach ($methods as $method => $result) {
+ // Hide passed tests from report
+ if ($result === true AND $hide_passed === true) {
+ continue;
+ }
+ printf("%-40.40s", $method);
+ if ($result === true) {
+ echo Kohana::lang("unit_test.passed"), "\n";
+ } else if ($result instanceof Kohana_Unit_Test_Exception) {
+ echo Kohana::lang("unit_test.failed"), "\n";
+ echo " ", html::specialchars($result->getMessage()), "\n";
+ echo " ", html::specialchars($result->getFile());
+ echo " ", "(" . Kohana::lang("unit_test.line") . " " . $result->getLine(), ")\n";
+ if ($result->getDebug() !== null) {
+ echo " ", "(", gettype($result->getDebug()), ") ",
+ html::specialchars(var_export($result->getDebug(), true)), "\n";
+ }
+ } else if ($result instanceof Exception) {
+ echo Kohana::lang("unit_test.error"), "\n";
+ if ($result->getMessage()) {
+ echo " ", html::specialchars($result->getMessage()), "\n";
+ }
+ echo " ", html::specialchars($result->getFile()), " (",
+ Kohana::lang("unit_test.line"), " ", $result->getLine(), ")\n";
+ }
+ }
+ }
+
+ echo str_repeat("=", 100), "\n";
+ printf(">> %s\t%s: %.2f%%\t%s: %d\t%s: %d\t%s: %d\t%s: %d\n",
+ $class,
+ Kohana::lang("unit_test.score"), $stats[$class]["score"],
+ Kohana::lang("unit_test.total"), $stats[$class]["total"],
+ Kohana::lang("unit_test.passed"), $stats[$class]["passed"],
+ Kohana::lang("unit_test.failed"), $stats[$class]["failed"],
+ Kohana::lang("unit_test.errors"), $stats[$class]["errors"]);
+ echo str_repeat("-", 100), "\n\n\n";
+}
+
+printf(">> TOTAL\t%s: %.2f%%\t%s: %d\t%s: %d\t%s: %d\t%s: %d\n",
+ Kohana::lang("unit_test.score"), 100 * ($totals["passed"] / $totals["total"]),
+ Kohana::lang("unit_test.total"), $totals["total"],
+ Kohana::lang("unit_test.passed"), $totals["passed"],
+ Kohana::lang("unit_test.failed"), $totals["failed"],
+ Kohana::lang("unit_test.errors"), $totals["errors"]);
diff --git a/modules/unit_test/config/unit_test.php b/modules/unit_test/config/unit_test.php
new file mode 100644
index 00000000..9da7711b
--- /dev/null
+++ b/modules/unit_test/config/unit_test.php
@@ -0,0 +1,15 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+/**
+ * @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..1481d9ff
--- /dev/null
+++ b/modules/unit_test/controllers/unit_test.php
@@ -0,0 +1,22 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+/**
+ * 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/i18n/en_US/unit_test.php b/modules/unit_test/i18n/en_US/unit_test.php
new file mode 100644
index 00000000..6d373b17
--- /dev/null
+++ b/modules/unit_test/i18n/en_US/unit_test.php
@@ -0,0 +1,43 @@
+<?php defined('SYSPATH') or die('No direct access allowed.');
+
+$lang = array
+(
+ 'invalid_test_path' => 'Failed to open test path: %s.',
+ 'duplicate_test_class' => 'Duplicate test class named %s found in %s.',
+ 'test_class_not_found' => 'No test class by the name of %s found in %s.',
+ 'test_class_extends' => '%s must extend Unit_Test_Case.',
+ 'no_tests_found' => 'No tests found',
+ 'score' => 'Score',
+ 'total' => 'Total',
+ 'passed' => 'Passed',
+ 'failed' => 'Failed',
+ 'error' => 'Error',
+ 'errors' => 'Errors',
+ 'line' => 'line',
+ 'assert_true' => 'assert_true: Expected true, but was given (%s) %s.',
+ 'assert_true_strict' => 'assert_true_strict: Expected (boolean) true, but was given (%s) %s.',
+ 'assert_false' => 'assert_false: Expected false, but was given (%s) %s.',
+ 'assert_false_strict' => 'assert_false_strict: Expected (boolean) false, but was given (%s) %s.',
+ 'assert_equal' => 'assert_equal: Expected (%s) %s, but was given (%s) %s.',
+ 'assert_not_equal' => 'assert_not_equal: Expected not (%s) %s, but was given (%s) %s.',
+ 'assert_same' => 'assert_same: Expected (%s) %s, but was given (%s) %s.',
+ 'assert_not_same' => 'assert_not_same: Expected not (%s) %s, but was given (%s) %s.',
+ 'assert_boolean' => 'assert_boolean: Expected a boolean, but was given (%s) %s.',
+ 'assert_not_boolean' => 'assert_not_boolean: Expected not a boolean, but was given (%s) %s.',
+ 'assert_integer' => 'assert_integer: Expected an integer, but was given (%s) %s.',
+ 'assert_not_integer' => 'assert_not_integer: Expected not an integer, but was given (%s) %s.',
+ 'assert_float' => 'assert_float: Expected a float, but was given (%s) %s.',
+ 'assert_not_float' => 'assert_not_float: Expected not a float, but was given (%s) %s.',
+ 'assert_array' => 'assert_array: Expected an array, but was given (%s) %s.',
+ 'assert_array_key' => 'assert_array_key: Expected a valid key, but was given (%s) %s.',
+ 'assert_in_array' => 'assert_in_array: Expected a valid value, but was given (%s) %s.',
+ 'assert_not_array' => 'assert_not_array: Expected not an array, but was given (%s) %s.',
+ 'assert_object' => 'assert_object: Expected an object, but was given (%s) %s.',
+ 'assert_not_object' => 'assert_not_object: Expected not an object, but was given (%s) %s.',
+ 'assert_null' => 'assert_null: Expected null, but was given (%s) %s.',
+ 'assert_not_null' => 'assert_not_null: Expected not null, but was given (%s) %s.',
+ 'assert_empty' => 'assert_empty: Expected an empty value, but was given (%s) %s.',
+ 'assert_not_empty' => 'assert_not_empty: Expected not an empty value, but was given (%s) %s.',
+ 'assert_pattern' => 'assert_pattern: Expected %s to match %s.',
+ 'assert_not_pattern' => 'assert_not_pattern: Expected %s to not match %s.',
+);
diff --git a/modules/unit_test/i18n/es_ES/unit_test.php b/modules/unit_test/i18n/es_ES/unit_test.php
new file mode 100644
index 00000000..1d0907e8
--- /dev/null
+++ b/modules/unit_test/i18n/es_ES/unit_test.php
@@ -0,0 +1,43 @@
+<?php defined('SYSPATH') or die('No direct access allowed.');
+
+$lang = array
+(
+ 'invalid_test_path' => 'Fallo al abrir la ruta del test: %s.',
+ 'duplicate_test_class' => 'Se ha encontrado un nombre de clase %s duplicado en %s.',
+ 'test_class_not_found' => 'No se ha encontrado una clase de test con el nombre %s en %s.',
+ 'test_class_extends' => '%s debe extender Unit_Test_Case.',
+ 'no_tests_found' => 'No se ha encontraro el test',
+ 'score' => 'Puntuación',
+ 'total' => 'Total',
+ 'passed' => 'Pasado',
+ 'failed' => 'Fallo',
+ 'error' => 'Error',
+ 'errors' => 'Errores',
+ 'line' => 'linea',
+ 'assert_true' => 'assert_true: Se esperaba true, pero se ha entregado (%s) %s.',
+ 'assert_true_strict' => 'assert_true_strict: Se esperaba (boolean) true, pero se ha entregado (%s) %s.',
+ 'assert_false' => 'assert_false: Se esperaba false, pero se ha entregado (%s) %s.',
+ 'assert_false_strict' => 'assert_false_strict: Se esperaba (boolean) false, pero se ha entregado (%s) %s.',
+ 'assert_equal' => 'assert_equal: Se esperaba (%s) %s, pero se ha entregado (%s) %s.',
+ 'assert_not_equal' => 'assert_not_equal: No se esperaba (%s) %s, pero se ha entregado (%s) %s.',
+ 'assert_same' => 'assert_same: Se esperaba (%s) %s, pero se ha entregado (%s) %s.',
+ 'assert_not_same' => 'assert_not_same: No se esperaba (%s) %s, pero se ha entregado (%s) %s.',
+ 'assert_boolean' => 'assert_boolean: Se esperaba un valor boolean, pero se ha entregado (%s) %s.',
+ 'assert_not_boolean' => 'assert_not_boolean: No se esperaba un valor boolean, pero se ha entregado (%s) %s.',
+ 'assert_integer' => 'assert_integer: Se esperaba un entero, pero se ha entregado (%s) %s.',
+ 'assert_not_integer' => 'assert_not_integer: No se esperaba un entero, pero se ha entregado (%s) %s.',
+ 'assert_float' => 'assert_float: Se esperaba una coma flotante, pero se ha entregado (%s) %s.',
+ 'assert_not_float' => 'assert_not_float: No se esperaba una cma flotante, pero se ha entregado (%s) %s.',
+ 'assert_array' => 'assert_array: Se esperaba una matriz, pero se ha entregado (%s) %s.',
+ 'assert_array_key' => 'assert_array_key: Se esperaba una clave valida, pero se ha entregado (%s) %s.',
+ 'assert_in_array' => 'assert_in_array: Se esperaba un valor valido, pero se ha entregado (%s) %s.',
+ 'assert_not_array' => 'assert_not_array: No se esperaba una matriz, pero se ha entregado (%s) %s.',
+ 'assert_object' => 'assert_object: Se esperaba un objecto, pero se ha entregado (%s) %s.',
+ 'assert_not_object' => 'assert_not_object: No se esperaba un objecto, pero se ha entregado (%s) %s.',
+ 'assert_null' => 'assert_null: Se esperaba null, pero se ha entregado (%s) %s.',
+ 'assert_not_null' => 'assert_not_null: No se esperaba null, pero se ha entregado (%s) %s.',
+ 'assert_empty' => 'assert_empty: Se esperaba un valor vacio, pero se ha entregado (%s) %s.',
+ 'assert_not_empty' => 'assert_not_empty: No se esperaba un valor vacio, pero se ha entregado (%s) %s.',
+ 'assert_pattern' => 'assert_pattern: Se esperaba que %s coincidiera %s.',
+ 'assert_not_pattern' => 'assert_not_pattern: Se esperaba que %s no coincidiera %s.',
+);
diff --git a/modules/unit_test/i18n/pt_BR/unit_test.php b/modules/unit_test/i18n/pt_BR/unit_test.php
new file mode 100644
index 00000000..91688ba1
--- /dev/null
+++ b/modules/unit_test/i18n/pt_BR/unit_test.php
@@ -0,0 +1,39 @@
+<?php defined('SYSPATH') or die('No direct access allowed.');
+
+$lang = array
+(
+ 'invalid_test_path' => 'Falha ao abrir o teste com o caminho: %s.',
+ 'duplicate_test_class' => 'Classe de teste %s com nome duplicado encontrado em %s.',
+ 'test_class_not_found' => 'No test class by the name of %s found in %s.',
+ 'test_class_extends' => '%s deve herdar Unit_Test_Case.',
+ 'no_tests_found' => 'Nenhum teste encontrado',
+ 'passed' => 'Passou',
+ 'failed' => 'Falhou',
+ 'error' => 'Erro',
+ 'errors' => 'Erros',
+ 'line' => 'linha',
+ 'assert_true' => 'assert_true: Expected true, but was given (%s) %s.',
+ 'assert_true_strict' => 'assert_true_strict: Expected (boolean) true, but was given (%s) %s.',
+ 'assert_false' => 'assert_false: Expected false, but was given (%s) %s.',
+ 'assert_false_strict' => 'assert_false_strict: Expected (boolean) false, but was given (%s) %s.',
+ 'assert_equal' => 'assert_equal: Expected (%s) %s, but was given (%s) %s.',
+ 'assert_not_equal' => 'assert_not_equal: Expected not (%s) %s, but was given (%s) %s.',
+ 'assert_same' => 'assert_same: Expected (%s) %s, but was given (%s) %s.',
+ 'assert_not_same' => 'assert_not_same: Expected not (%s) %s, but was given (%s) %s.',
+ 'assert_boolean' => 'assert_boolean: Expected a boolean, but was given (%s) %s.',
+ 'assert_not_boolean' => 'assert_not_boolean: Expected not a boolean, but was given (%s) %s.',
+ 'assert_integer' => 'assert_integer: Expected an integer, but was given (%s) %s.',
+ 'assert_not_integer' => 'assert_not_integer: Expected not an integer, but was given (%s) %s.',
+ 'assert_float' => 'assert_float: Expected a float, but was given (%s) %s.',
+ 'assert_not_float' => 'assert_not_float: Expected not a float, but was given (%s) %s.',
+ 'assert_array' => 'assert_array: Expected an array, but was given (%s) %s.',
+ 'assert_not_array' => 'assert_not_array: Expected not an array, but was given (%s) %s.',
+ 'assert_object' => 'assert_object: Expected an object, but was given (%s) %s.',
+ 'assert_not_object' => 'assert_not_object: Expected not an object, but was given (%s) %s.',
+ 'assert_null' => 'assert_null: Expected null, but was given (%s) %s.',
+ 'assert_not_null' => 'assert_not_null: Expected not null, but was given (%s) %s.',
+ 'assert_empty' => 'assert_empty: Expected an empty value, but was given (%s) %s.',
+ 'assert_not_empty' => 'assert_not_empty: Expected not an empty value, but was given (%s) %s.',
+ 'assert_pattern' => 'assert_pattern: Expected %s to match %s.',
+ 'assert_not_pattern' => 'assert_not_pattern: Expected %s to not match %s.',
+);
diff --git a/modules/unit_test/i18n/ru_RU/unit_test.php b/modules/unit_test/i18n/ru_RU/unit_test.php
new file mode 100644
index 00000000..7c0960eb
--- /dev/null
+++ b/modules/unit_test/i18n/ru_RU/unit_test.php
@@ -0,0 +1,43 @@
+<?php defined('SYSPATH') or die('No direct access allowed.');
+
+$lang = array
+(
+ 'invalid_test_path' => 'Не удалось открыть путь теста: %s.',
+ 'duplicate_test_class' => 'Дубль тестового класса "%s" найден в %s.',
+ 'test_class_not_found' => 'Тестовый класс с именем "%s" не найден в %s.',
+ 'test_class_extends' => '%s должен быть наследником класса Unit_Test_Case.',
+ 'no_tests_found' => 'Тесты не найдены',
+ 'score' => 'Счёт',
+ 'total' => 'Всего',
+ 'passed' => 'Пройдено',
+ 'failed' => 'Завалено',
+ 'error' => 'Ошибка',
+ 'errors' => 'Ошибок',
+ 'line' => 'строка',
+ 'assert_true' => 'assert_true: Ожидалась истина, получено (%s) %s.',
+ 'assert_true_strict' => 'assert_true_strict: Ожидалась булевая истина, получено (%s) %s.',
+ 'assert_false' => 'assert_false: Ожидалась ложь, получено (%s) %s.',
+ 'assert_false_strict' => 'assert_false_strict: Ожидалась булевая истина, получено (%s) %s.',
+ 'assert_equal' => 'assert_equal: Ожидалось (%s) %s, получено (%s) %s.',
+ 'assert_not_equal' => 'assert_not_equal: Ожидалось не (%s) %s, получено (%s) %s.',
+ 'assert_same' => 'assert_same: Ожидалось (%s) %s, получено (%s) %s.',
+ 'assert_not_same' => 'assert_not_same: Ожидалось не (%s) %s, получено (%s) %s.',
+ 'assert_boolean' => 'assert_boolean: Ожидалось булевое значение, получено (%s) %s.',
+ 'assert_not_boolean' => 'assert_not_boolean: Ожидалось не булевое значение, получено (%s) %s.',
+ 'assert_integer' => 'assert_integer: Ожидалось целочисленное значение, получено (%s) %s.',
+ 'assert_not_integer' => 'assert_not_integer: Ожидалось не целочисленное значение, получено (%s) %s.',
+ 'assert_float' => 'assert_float: Ожидалось значение с плавающей точкой, получено (%s) %s.',
+ 'assert_not_float' => 'assert_not_float: Ожидалось не значение с плавающей точкой, получено (%s) %s.',
+ 'assert_array' => 'assert_array: Ожидался массив, получено (%s) %s.',
+ 'assert_array_key' => 'assert_array_key: Ожидался индекс массива, получено (%s) %s.',
+ 'assert_in_array' => 'assert_in_array: Ожидался элемент массива, получено (%s) %s.',
+ 'assert_not_array' => 'assert_not_array: Ожидался не элемент массива, получено (%s) %s.',
+ 'assert_object' => 'assert_object: Ожидался объект, получено (%s) %s.',
+ 'assert_not_object' => 'assert_not_object: Ожидался не объект, получено (%s) %s.',
+ 'assert_null' => 'assert_null: Ожидался null, получено (%s) %s.',
+ 'assert_not_null' => 'assert_not_null: Ожидался не null, получено (%s) %s.',
+ 'assert_empty' => 'assert_empty: Ожидалось пустое значение, получено (%s) %s.',
+ 'assert_not_empty' => 'assert_not_empty: Ожидалось не пустое значение, получено (%s) %s.',
+ 'assert_pattern' => 'assert_pattern: Ожидалось %s равное %s.',
+ 'assert_not_pattern' => 'assert_not_pattern: Ожидалось %s не равное %s.',
+);
diff --git a/modules/unit_test/libraries/Unit_Test.php b/modules/unit_test/libraries/Unit_Test.php
new file mode 100644
index 00000000..4e22f501
--- /dev/null
+++ b/modules/unit_test/libraries/Unit_Test.php
@@ -0,0 +1,480 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+/**
+ * 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/tests/Example_Test.php b/modules/unit_test/tests/Example_Test.php
new file mode 100644
index 00000000..4abaf0cd
--- /dev/null
+++ b/modules/unit_test/tests/Example_Test.php
@@ -0,0 +1,103 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+/**
+ * Example Test.
+ *
+ * $Id$
+ *
+ * @package Unit_Test
+ * @author Kohana Team
+ * @copyright (c) 2007-2008 Kohana Team
+ * @license http://kohanaphp.com/license.html
+ */
+class Example_Test extends Unit_Test_Case {
+
+ // Disable this Test class?
+ const DISABLED = FALSE;
+
+ public $setup_has_run = FALSE;
+
+ public function setup()
+ {
+ $this->setup_has_run = TRUE;
+ }
+
+ public function setup_test()
+ {
+ $this->assert_true_strict($this->setup_has_run);
+ }
+
+ public function true_false_test()
+ {
+ $var = TRUE;
+ $this
+ ->assert_true($var)
+ ->assert_true_strict($var)
+ ->assert_false( ! $var)
+ ->assert_false_strict( ! $var);
+ }
+
+ public function equal_same_test()
+ {
+ $var = '5';
+ $this
+ ->assert_equal($var, 5)
+ ->assert_not_equal($var, 6)
+ ->assert_same($var, '5')
+ ->assert_not_same($var, 5);
+ }
+
+ public function type_test()
+ {
+ $this
+ ->assert_boolean(TRUE)
+ ->assert_not_boolean('TRUE')
+ ->assert_integer(123)
+ ->assert_not_integer('123')
+ ->assert_float(1.23)
+ ->assert_not_float(123)
+ ->assert_array(array(1, 2, 3))
+ ->assert_not_array('array()')
+ ->assert_object(new stdClass)
+ ->assert_not_object('X')
+ ->assert_null(NULL)
+ ->assert_not_null(0)
+ ->assert_empty('0')
+ ->assert_not_empty('1');
+ }
+
+ public function pattern_test()
+ {
+ $var = "Kohana\n";
+ $this
+ ->assert_pattern($var, '/^Kohana$/')
+ ->assert_not_pattern($var, '/^Kohana$/D');
+ }
+
+ public function array_key_test()
+ {
+ $array = array('a' => 'A', 'b' => 'B');
+ $this->assert_array_key('a', $array);
+ }
+
+ public function in_array_test()
+ {
+ $array = array('X', 'Y', 'Z');
+ $this->assert_in_array('X', $array);
+ }
+
+ public function debug_example_test()
+ {
+ foreach (array(1, 5, 6, 12, 65, 128, 9562) as $var)
+ {
+ // By supplying $var in the debug parameter,
+ // we can see on which number this test fails.
+ $this->assert_true($var < 100, $var);
+ }
+ }
+
+ public function error_test()
+ {
+ throw new Exception;
+ }
+
+}
diff --git a/modules/unit_test/tests/Valid_Helper_Test.php b/modules/unit_test/tests/Valid_Helper_Test.php
new file mode 100644
index 00000000..bf35064b
--- /dev/null
+++ b/modules/unit_test/tests/Valid_Helper_Test.php
@@ -0,0 +1,121 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+/**
+ * Valid Helper Test.
+ *
+ * @package Unit_Test
+ * @author Kohana Team
+ * @copyright (c) 2007-2008 Kohana Team
+ * @license http://kohanaphp.com/license.html
+ */
+class Valid_Helper_Test extends Unit_Test_Case {
+
+ // Disable this Test class?
+ const DISABLED = FALSE;
+
+ public function valid_email_test()
+ {
+ $this
+ ->assert_true_strict(valid::email('address@domain.tld'))
+ ->assert_false_strict(valid::email('address@domain'));
+ }
+
+ public function valid_email_rfc_test()
+ {
+ $this
+ ->assert_true_strict(valid::email_rfc('address@domain'))
+ ->assert_false_strict(valid::email_rfc('address.domain'));
+ }
+
+ public function valid_email_domain_test()
+ {
+ // not implemented on windows platform
+ $var1 = (KOHANA_IS_WIN) ? TRUE : valid::email_domain('address@gmail.tld');
+ $var2 = (KOHANA_IS_WIN) ? FALSE : valid::email_domain('address@domain-should_not-exist.tld');
+ $this
+ ->assert_true_strict($var1)
+ ->assert_false_strict($var2);
+ }
+ public function valid_url_test()
+ {
+ $this
+ ->assert_true_strict(valid::url('http://www.kohanaphp.com'))
+ ->assert_false_strict(valid::url('www.kohanaphp.com'));
+ }
+
+ public function valid_ip_test()
+ {
+ $this
+ ->assert_true_strict(valid::ip('75.125.175.50')) // valid - kohanaphp.com
+ ->assert_true_strict(valid::ip('127.0.0.1')) // valid - local loopback
+ ->assert_false_strict(valid::ip('256.257.258.259')) // invalid ip
+ ->assert_false_strict(valid::ip('255.255.255.255')) // invalid - reserved range
+ ->assert_false_strict(valid::ip('192.168.0.1')); // invalid - private range
+ }
+
+ public function valid_credit_card_test()
+ {
+ $this
+ ->assert_true_strict(valid::credit_card('4222222222222')) // valid visa test nr
+ ->assert_true_strict(valid::credit_card('4012888888881881')) // valid visa test nr
+ ->assert_true_strict(valid::credit_card('5105105105105100')) // valid mastercard test nr
+ ->assert_true_strict(valid::credit_card('6011111111111117')) // valid discover test nr
+ ->assert_false_strict(valid::credit_card('6011111111111117', 'visa')); // invalid visa test nr
+ }
+
+ public function valid_phone_test()
+ {
+ $this
+ ->assert_true_strict(valid::phone('0163634840'))
+ ->assert_true_strict(valid::phone('+27173634840'))
+ ->assert_false_strict(valid::phone('123578'));
+ }
+
+ public function valid_alpha_test()
+ {
+ $this
+ ->assert_true_strict(valid::alpha('abc'))
+ ->assert_false_strict(valid::alpha('123'));
+ }
+
+ public function valid_alpha_numeric_test()
+ {
+ $this
+ ->assert_true_strict(valid::alpha_numeric('abc123'))
+ ->assert_false_strict(valid::alpha_numeric('123*.*'));
+ }
+
+ public function valid_alpha_dash_test()
+ {
+ $this
+ ->assert_true_strict(valid::alpha_dash('_ab-12'))
+ ->assert_false_strict(valid::alpha_dash('ab_ 123 !'));
+ }
+
+ public function valid_digit_test()
+ {
+ $this
+ ->assert_true_strict(valid::digit('123'))
+ ->assert_false_strict(valid::digit('abc'));
+ }
+
+ public function valid_numeric_test()
+ {
+ $this
+ ->assert_true_strict(valid::numeric(-12.99))
+ ->assert_false_strict(valid::numeric('123_4'));
+ }
+
+ public function valid_standard_text_test()
+ {
+ $this
+ ->assert_true_strict(valid::standard_text('some valid_text-to.test 123'))
+ ->assert_false_strict(valid::standard_text('some !real| ju0n_%k'));
+ }
+
+ public function valid_decimal_test()
+ {
+ $this
+ ->assert_true_strict(valid::decimal(12.99))
+ ->assert_false_strict(valid::decimal(12,99));
+ }
+} // End Valid Helper Test Controller
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..82ccf498
--- /dev/null
+++ b/modules/unit_test/views/kohana_unit_test.php
@@ -0,0 +1,169 @@
+<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>