|
<?php defined('SYSPATH') or die('No direct script access.');
|
|
/*
|
|
* This file is part of open source system FreenetIS
|
|
* and it is released under GPLv3 licence.
|
|
*
|
|
* More info about licence can be found:
|
|
* http://www.gnu.org/licenses/gpl-3.0.html
|
|
*
|
|
* More info about project can be found:
|
|
* http://www.freenetis.org/
|
|
*
|
|
*/
|
|
|
|
/** File with XML config generated by generate_unit_config.pl at same path */
|
|
define("filename", APPPATH . "vendors/unit_tester/unit_testing_config.xml");
|
|
|
|
/**
|
|
* Exception handler for disabling Kohana handler
|
|
* @param Exception $exception
|
|
*/
|
|
function unit_tester_exception_handler($exception)
|
|
{
|
|
throw $exception;
|
|
}
|
|
|
|
/**
|
|
* Error handler for disabling Kohana handler
|
|
* @param Exception $exception
|
|
*/
|
|
function unit_tester_error_handler($errno, $errstr, $errfile, $errline)
|
|
{
|
|
throw new Exception($errstr, $errno);
|
|
}
|
|
|
|
/**
|
|
* Fatal error handler
|
|
*/
|
|
function unit_tester_handle_shutdown()
|
|
{
|
|
$error = error_get_last();
|
|
if ($error !== NULL)
|
|
{
|
|
throw new Exception($error['message']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unit tester controller, test models, helpers and controllers.
|
|
* Invoke testers and displays results.
|
|
*
|
|
* Unit tester has to be enabled in config file, because it is not secure to run
|
|
* it in product server.
|
|
*
|
|
* Unit tester is not called directly, but using sh script stored in:
|
|
*
|
|
* /application/vendors/unit_tester/tester.sh
|
|
*
|
|
* For help see:
|
|
*
|
|
* $ /application/vendors/unit_tester/tester.sh --help
|
|
*
|
|
* @see http://wiki.freenetis.org/index.php/Automatické_testování
|
|
* @author Ondřej Fibich
|
|
* @package Controller
|
|
* @version 1.2
|
|
*/
|
|
class Unit_tester_Controller extends Controller
|
|
{
|
|
/** Type for test of models */
|
|
const MODELS = 1;
|
|
/** Type for test of constrollers */
|
|
const CONTROLLERS = 2;
|
|
/** Type for test of helpers */
|
|
const HELPERS = 3;
|
|
|
|
/**
|
|
* Test models
|
|
*
|
|
* @param mixed $stats Indicator if stats are enabled
|
|
*/
|
|
public function models($stats = NULL)
|
|
{
|
|
$this->test(self::MODELS, !empty($stats));
|
|
}
|
|
|
|
/**
|
|
* Test helpers
|
|
*/
|
|
public function helpers()
|
|
{
|
|
$this->test(self::HELPERS, FALSE);
|
|
}
|
|
|
|
/**
|
|
* Invokes test suites and displays results
|
|
*
|
|
* @param type $type One of ALL, MODELS, CONTROLLERS, HELPERS
|
|
* which can be combined using bit or
|
|
* @param bool $stats Indicator if stats are enabled
|
|
*/
|
|
private function test($type, $stats = FALSE)
|
|
{
|
|
// check type of test
|
|
if ($type < self::MODELS || $type > self::HELPERS)
|
|
{
|
|
die("Wrong argument.");
|
|
}
|
|
// check access
|
|
if (!Config::get('unit_tester'))
|
|
{
|
|
echo "Enable Unit Test by adding ";
|
|
echo "<code>\$config['unit_tester'] = TRUE;</code>";
|
|
echo " into <code>config.php</code>.";
|
|
exit();
|
|
}
|
|
// overload Kohana error handlers
|
|
register_shutdown_function('unit_tester_handle_shutdown');
|
|
set_error_handler('unit_tester_error_handler');
|
|
set_exception_handler('unit_tester_exception_handler');
|
|
// extend safe limit
|
|
set_time_limit(60);
|
|
// results
|
|
$results = array();
|
|
/* testing */
|
|
try
|
|
{
|
|
// test models
|
|
if ($type == self::MODELS)
|
|
{
|
|
$info_array = $this->test_util("model", $stats);
|
|
$results["title"] = "Models";
|
|
$results["valids"] = $info_array[0];
|
|
$results["errors"] = $info_array[1];
|
|
}
|
|
// test helpers
|
|
else if ($type == self::HELPERS)
|
|
{
|
|
$info_array = $this->test_util("helper", $stats);
|
|
$results["title"] = "Helpers";
|
|
$results["valids"] = $info_array[0];
|
|
$results["errors"] = $info_array[1];
|
|
}
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
die("<pre>" . $e . "</pre>");
|
|
}
|
|
/* Display results */
|
|
$view = new View("unit_tester/index");
|
|
$view->title = "Unit tester controller";
|
|
$view->results = $results;
|
|
$view->stats = $stats;
|
|
$view->render(TRUE);
|
|
}
|
|
|
|
/**
|
|
* Testing utility.
|
|
* Check parse errors and exception throws from objects.
|
|
* @param string $tag Tag model or helper
|
|
* @param bool $stats Indicator if stats are enabled
|
|
* @return array Array with valid and error array.
|
|
* Valid array contaions counts of valid methods and models.
|
|
* Item of error array contains keys obj, type, error, trace.
|
|
*/
|
|
private function test_util($tag, $stats)
|
|
{
|
|
$errors = array();
|
|
$valids = array
|
|
(
|
|
"models" => 0,
|
|
"methods" => 0
|
|
);
|
|
$f = false;
|
|
$xml_dom = new DOMDocument("1.0", "UTF-8");
|
|
|
|
// open file
|
|
if (($f = file_exists(filename)) === false)
|
|
{
|
|
echo "Cannot find file: `" . filename . "`\n";
|
|
echo "Run unit_testing_config.pl\n";
|
|
exit(1);
|
|
}
|
|
|
|
// read whole file
|
|
$source = file_get_contents(filename);
|
|
|
|
// parse file
|
|
if (!$xml_dom->loadXML($source))
|
|
{
|
|
echo "Cannot parse config file: `" . filename . "`\n";
|
|
exit(2);
|
|
}
|
|
|
|
ob_start();
|
|
|
|
$elements = $xml_dom->getElementsByTagName($tag);
|
|
|
|
// each model
|
|
foreach ($elements as $element)
|
|
{
|
|
$file_name = $element->getAttribute("name");
|
|
$file_path = APPPATH . $tag . "s/" . $file_name . EXT;
|
|
|
|
/* File exist catcher */
|
|
if (!file_exists($file_path))
|
|
{
|
|
$errors[] = array
|
|
(
|
|
"obj" => $file_name,
|
|
"type" => "FILE ERROR on " . $tag,
|
|
"trace" => null,
|
|
"error" => "Cannot find " . $tag . " file: `" . $file_path . "`\n"
|
|
);
|
|
// next file
|
|
continue;
|
|
}
|
|
|
|
$class_name = "";
|
|
/* Load model */
|
|
if ($tag == "model")
|
|
{
|
|
$class_name = ucfirst($file_name) . "_Model";
|
|
}
|
|
else
|
|
{
|
|
$class_name = $file_name;
|
|
|
|
if (!class_exists($class_name))
|
|
{
|
|
if (class_exists($class_name . "_Core"))
|
|
{
|
|
$class_name = $class_name . "_Core";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!class_exists($class_name))
|
|
{
|
|
$errors[] = array
|
|
(
|
|
"obj" => $class_name,
|
|
"type" => "EXCEPTION ERROR in " . $tag,
|
|
"trace" => null,
|
|
"error" => "Model does not exists."
|
|
);
|
|
// next model
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
$obj = new $class_name;
|
|
$valids["models"]++;
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
$errors[] = array
|
|
(
|
|
"obj" => $class_name,
|
|
"type" => "EXCEPTION ERROR during loading " . $tag,
|
|
"trace" => $e->getTraceAsString(),
|
|
"error" => $e->__toString()
|
|
);
|
|
// next file
|
|
continue;
|
|
}
|
|
|
|
/* Check object methods */
|
|
$methods = $element->getElementsByTagName("method");
|
|
|
|
foreach ($methods as $method)
|
|
{
|
|
$method_name = $method->getAttribute("name");
|
|
$attributes = array();
|
|
|
|
/* Get attributes */
|
|
$attrs = $method->getElementsByTagName("attributes")
|
|
->item(0)
|
|
->getElementsByTagName("attribute");
|
|
|
|
foreach ($attrs as $attr)
|
|
{
|
|
$attr_name = $attr->getAttribute("name");
|
|
$attributes[$attr_name] = $attr->getAttribute("default_value");
|
|
|
|
if (preg_match("/^array\(.*\)$/", $attributes[$attr_name]))
|
|
{
|
|
$attributes[$attr_name] = self::array_parse($attributes[$attr_name]);
|
|
}
|
|
}
|
|
|
|
/* Call for all inputs */
|
|
$inputs = $method->getElementsByTagName("values")
|
|
->item(0)
|
|
->getElementsByTagName("input");
|
|
|
|
foreach ($inputs as $input)
|
|
{
|
|
$unprocessed_input = array();
|
|
/* Get params */
|
|
$paramsarray = array();
|
|
$i = 0;
|
|
|
|
if ($input->hasChildNodes())
|
|
{
|
|
$params = $input->getElementsByTagName("param");
|
|
|
|
foreach ($params as $param)
|
|
{
|
|
$paramsarray[$i] = $param->getAttribute("value");
|
|
$unprocessed_input[$i] = $paramsarray[$i];
|
|
|
|
if (strtolower($paramsarray[$i]) == 'true')
|
|
{ // bool true
|
|
$paramsarray[$i] = true;
|
|
}
|
|
else if (strtolower($paramsarray[$i]) == 'false')
|
|
{ // bool false
|
|
$paramsarray[$i] = false;
|
|
}
|
|
else if (preg_match("/^array\(.*\)$/", $paramsarray[$i]))
|
|
{ // array
|
|
$paramsarray[$i] = self::array_parse($paramsarray[$i]);
|
|
}
|
|
else
|
|
{
|
|
$unprocessed_input[$i] = "'" . $paramsarray[$i] . "'";
|
|
}
|
|
|
|
$i++;
|
|
}
|
|
}
|
|
|
|
/* Call method */
|
|
try
|
|
{
|
|
if ($stats)
|
|
{
|
|
$mtime = microtime(true);
|
|
}
|
|
|
|
call_user_func_array(array($obj, $method_name), $paramsarray);
|
|
$valids["methods"]++;
|
|
|
|
if ($stats)
|
|
{
|
|
$valids[] = array
|
|
(
|
|
"obj" => $class_name . "#" . $method_name,
|
|
"type" => $method_name . "(". implode(",", $unprocessed_input).")",
|
|
"time" => round((microtime(true) - $mtime), 4)
|
|
);
|
|
}
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
$errors[] = array
|
|
(
|
|
"obj" => $class_name . "#" . $method_name,
|
|
"type" => "EXCEPTION ERROR in " . $tag . " during call "
|
|
. $method_name . "(". implode(",", $unprocessed_input).")",
|
|
"trace" => $e->getTraceAsString(),
|
|
"error" => $e->getMessage()
|
|
);
|
|
// next
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ob_clean();
|
|
|
|
return array($valids, $errors);
|
|
}
|
|
|
|
/**
|
|
* Parse string with array
|
|
* @param type $str String with array PHP syntax
|
|
* @return array Parsed array or null on error
|
|
*/
|
|
public static function array_parse($str)
|
|
{
|
|
if ($str === "array()")
|
|
{
|
|
return array();
|
|
}
|
|
else
|
|
{
|
|
// get content of array
|
|
$str = substr($str, 6);
|
|
$str = substr($str, 0, strlen($str) - 1);
|
|
// check content
|
|
$items = preg_split("/\s*,\s*/", $str);
|
|
$result = array();
|
|
// for each item of array
|
|
foreach ($items as $item)
|
|
{
|
|
if (strlen($item) > 0)
|
|
{
|
|
if (preg_match("/^[\"']?(.*?)[\"']?\s*=>\s*[\"']?(.*?)[\"']?$/", $item, $r))
|
|
{
|
|
$result[$r[1]] = $r[2];
|
|
}
|
|
else if (preg_match("/^[\"']?(.*?)[\"']?$/", $item, $r))
|
|
{
|
|
$result[] = $r[1];
|
|
}
|
|
}
|
|
}
|
|
// return parsed array
|
|
return $result;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
}
|