PageRenderTime 27ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/unit_test/libraries/Unit_Test.php

http://github.com/gallery/gallery3
PHP | 551 lines | 364 code | 104 blank | 83 comment | 51 complexity | 420904d36c2c11160dc901704ee12585 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php defined('SYSPATH') OR die('No direct access allowed.');
  2. /**
  3. * Unit_Test library.
  4. *
  5. * $Id: Unit_Test.php 4367 2009-05-27 21:23:57Z samsoir $
  6. *
  7. * @package Unit_Test
  8. * @author Kohana Team
  9. * @copyright (c) 2007-2008 Kohana Team
  10. * @license http://kohanaphp.com/license.html
  11. */
  12. class Unit_Test_Core {
  13. // The path(s) to recursively scan for tests
  14. protected $paths = array();
  15. // The results of all tests from every test class
  16. protected $results = array();
  17. // Statistics for every test class
  18. protected $stats = array();
  19. public static $lang = array(
  20. 'class' => 'Class',
  21. 'method' => 'Method',
  22. 'invalid_test_path' => 'Failed to open test path: %s.',
  23. 'duplicate_test_class' => 'Duplicate test class named %s found in %s.',
  24. 'test_class_not_found' => 'No test class by the name of %s found in %s.',
  25. 'test_class_extends' => '%s must extend Unit_Test_Case.',
  26. 'no_tests_found' => 'No tests found',
  27. 'score' => 'Score',
  28. 'total' => 'Total',
  29. 'passed' => 'Passed',
  30. 'failed' => 'Failed',
  31. 'error' => 'Error',
  32. 'errors' => 'Errors',
  33. 'line' => 'line',
  34. 'assert_true' => 'assert_true: Expected true, but was given (%s) %s.',
  35. 'assert_true_strict' => 'assert_true_strict: Expected (boolean) true, but was given (%s) %s.',
  36. 'assert_false' => 'assert_false: Expected false, but was given (%s) %s.',
  37. 'assert_false_strict' => 'assert_false_strict: Expected (boolean) false, but was given (%s) %s.',
  38. 'assert_equal' => 'assert_equal: Expected (%s) %s, but was given (%s) %s.',
  39. 'assert_not_equal' => 'assert_not_equal: Expected not (%s) %s, but was given (%s) %s.',
  40. 'assert_same' => 'assert_same: Expected (%s) %s, but was given (%s) %s.',
  41. 'assert_not_same' => 'assert_not_same: Expected not (%s) %s, but was given (%s) %s.',
  42. 'assert_boolean' => 'assert_boolean: Expected a boolean, but was given (%s) %s.',
  43. 'assert_not_boolean' => 'assert_not_boolean: Expected not a boolean, but was given (%s) %s.',
  44. 'assert_integer' => 'assert_integer: Expected an integer, but was given (%s) %s.',
  45. 'assert_not_integer' => 'assert_not_integer: Expected not an integer, but was given (%s) %s.',
  46. 'assert_float' => 'assert_float: Expected a float, but was given (%s) %s.',
  47. 'assert_not_float' => 'assert_not_float: Expected not a float, but was given (%s) %s.',
  48. 'assert_array' => 'assert_array: Expected an array, but was given (%s) %s.',
  49. 'assert_array_key' => 'assert_array_key: Expected a valid key, but was given (%s) %s.',
  50. 'assert_in_array' => 'assert_in_array: Expected a valid value, but was given (%s) %s.',
  51. 'assert_not_array' => 'assert_not_array: Expected not an array, but was given (%s) %s.',
  52. 'assert_object' => 'assert_object: Expected an object, but was given (%s) %s.',
  53. 'assert_not_object' => 'assert_not_object: Expected not an object, but was given (%s) %s.',
  54. 'assert_null' => 'assert_null: Expected null, but was given (%s) %s.',
  55. 'assert_not_null' => 'assert_not_null: Expected not null, but was given (%s) %s.',
  56. 'assert_empty' => 'assert_empty: Expected an empty value, but was given (%s) %s.',
  57. 'assert_not_empty' => 'assert_not_empty: Expected not an empty value, but was given (%s) %s.',
  58. 'assert_pattern' => 'assert_pattern: Expected %s to match %s.',
  59. 'assert_not_pattern' => 'assert_not_pattern: Expected %s to not match %s.'
  60. );
  61. /**
  62. * Sets the test path(s), runs the tests inside and stores the results.
  63. *
  64. * @param array test path(s)
  65. * @param string filter (regular expression)
  66. * @return void
  67. */
  68. public function __construct($extra_paths=array(), $filter=null)
  69. {
  70. // Merge possible default test path(s) from config with the rest
  71. $paths = array_merge($extra_paths, Kohana::config('unit_test.paths', FALSE, FALSE));
  72. // Normalize all test paths
  73. foreach ($paths as $path)
  74. {
  75. $path = str_replace('\\', '/', realpath((string) $path));
  76. }
  77. // Take out duplicate test paths after normalization
  78. $this->paths = array_unique($paths);
  79. // Loop over each given test path
  80. foreach ($this->paths as $path)
  81. {
  82. // Validate test path
  83. if ( ! is_dir($path))
  84. throw new Kohana_Exception('unit_test.invalid_test_path', $path);
  85. // Recursively iterate over each file in the test path
  86. foreach
  87. (
  88. new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME))
  89. as $path => $file
  90. )
  91. {
  92. // Normalize path
  93. $path = str_replace('\\', '/', $path);
  94. // Skip files without "_Test" suffix
  95. if ( ! $file->isFile() OR substr($path, -9) !== '_Test'.EXT)
  96. continue;
  97. // The class name should be the same as the file name
  98. $class = substr($path, strrpos($path, '/') + 1, -(strlen(EXT)));
  99. // Skip hidden files
  100. if ($class[0] === '.')
  101. continue;
  102. // Check for duplicate test class name
  103. if (class_exists($class, FALSE))
  104. throw new Kohana_Exception('unit_test.duplicate_test_class', $class, $path);
  105. // Include the test class
  106. include_once $path;
  107. // Check whether the test class has been found and loaded
  108. if ( ! class_exists($class, FALSE))
  109. throw new Kohana_Exception('unit_test.test_class_not_found', $class, $path);
  110. // Reverse-engineer Test class
  111. $reflector = new ReflectionClass($class);
  112. // Test classes must extend Unit_Test_Case
  113. if ( ! $reflector->isSubclassOf(new ReflectionClass('Unit_Test_Case')))
  114. throw new Kohana_Exception('unit_test.test_class_extends', $class);
  115. // Skip disabled Tests
  116. if ($reflector->getConstant('DISABLED') === TRUE)
  117. continue;
  118. // Initialize setup and teardown method triggers
  119. $setup = $teardown = FALSE;
  120. // Look for valid setup and teardown methods
  121. foreach (array('setup', 'teardown') as $method_name)
  122. {
  123. if ($reflector->hasMethod($method_name))
  124. {
  125. $method = new ReflectionMethod($class, $method_name);
  126. $$method_name = ($method->isPublic() AND ! $method->isStatic() AND $method->getNumberOfRequiredParameters() === 0);
  127. }
  128. }
  129. // Initialize test class results and stats
  130. $this->results[$class] = array();
  131. $this->stats[$class] = array
  132. (
  133. 'passed' => 0,
  134. 'failed' => 0,
  135. 'errors' => 0,
  136. 'total' => 0,
  137. 'score' => 0,
  138. );
  139. // Loop through all the class methods
  140. foreach ($reflector->getMethods() as $method)
  141. {
  142. // Skip invalid test methods
  143. if ( ! $method->isPublic() OR $method->isStatic() OR $method->getNumberOfRequiredParameters() !== 0)
  144. continue;
  145. if ($filter && !preg_match("/$filter/i", "$class::{$method->getName()}")) {
  146. continue;
  147. }
  148. // Test methods should be suffixed with "_test"
  149. if (substr($method_name = $method->getName(), -5) !== '_test')
  150. continue;
  151. // Instantiate Test class
  152. $object = new $class;
  153. try
  154. {
  155. // Run setup method
  156. if ($setup === TRUE)
  157. {
  158. $object->setup();
  159. }
  160. $e = null;
  161. try {
  162. // Enforce a time limit
  163. set_time_limit(30);
  164. // Run the actual test
  165. $object->$method_name();
  166. } catch (Exception $e) { }
  167. // Run teardown method
  168. if ($teardown === TRUE)
  169. {
  170. $object->teardown();
  171. }
  172. if ($e) {
  173. throw $e;
  174. }
  175. $this->stats[$class]['total']++;
  176. // Test passed
  177. $this->results[$class][$method_name] = TRUE;
  178. $this->stats[$class]['passed']++;
  179. }
  180. catch (Kohana_Unit_Test_Exception $e)
  181. {
  182. $this->stats[$class]['total']++;
  183. // Test failed
  184. $this->results[$class][$method_name] = $e;
  185. $this->stats[$class]['failed']++;
  186. }
  187. catch (Exception $e)
  188. {
  189. $this->stats[$class]['total']++;
  190. // Test error
  191. $this->results[$class][$method_name] = $e;
  192. $this->stats[$class]['errors']++;
  193. }
  194. // Calculate score
  195. $this->stats[$class]['score'] = $this->stats[$class]['passed'] * 100 / $this->stats[$class]['total'];
  196. // Cleanup
  197. unset($object);
  198. }
  199. if ($filter && $this->stats[$class]['total'] == 0) {
  200. unset($this->results[$class]);
  201. unset($this->stats[$class]);
  202. }
  203. }
  204. }
  205. }
  206. /**
  207. * Generates nice test results.
  208. *
  209. * @param boolean hide passed tests from the report
  210. * @return string rendered test results html
  211. */
  212. public function report($hide_passed = NULL)
  213. {
  214. // No tests found
  215. if (empty($this->results))
  216. return sprintf(self::$lang['no_tests_found']);
  217. // Hide passed tests from the report?
  218. $hide_passed = (bool) (($hide_passed !== NULL) ? $hide_passed : Kohana::config('unit_test.hide_passed', FALSE, FALSE));
  219. if (PHP_SAPI == 'cli')
  220. {
  221. $report = View::factory('kohana_unit_test_cli');
  222. }
  223. else
  224. {
  225. $report = View::factory('kohana_unit_test');
  226. }
  227. // Render unit_test report
  228. return $report->set('results', $this->results)
  229. ->set('stats', $this->stats)
  230. ->set('hide_passed', $hide_passed)
  231. ->render();
  232. }
  233. /**
  234. * Magically convert this object to a string.
  235. *
  236. * @return string test report
  237. */
  238. public function __toString()
  239. {
  240. return $this->report();
  241. }
  242. /**
  243. * Magically gets a Unit_Test property.
  244. *
  245. * @param string property name
  246. * @return mixed variable value if the property is found
  247. * @return void if the property is not found
  248. */
  249. public function __get($key)
  250. {
  251. if (isset($this->$key))
  252. return $this->$key;
  253. }
  254. } // End Unit_Test_Core
  255. abstract class Unit_Test_Case {
  256. public function assert_true($value, $debug = NULL)
  257. {
  258. if ($value != TRUE)
  259. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_true'], gettype($value), var_export($value, TRUE)), $debug);
  260. return $this;
  261. }
  262. public function assert_true_strict($value, $debug = NULL)
  263. {
  264. if ($value !== TRUE)
  265. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_true_strict'], gettype($value), var_export($value, TRUE)), $debug);
  266. return $this;
  267. }
  268. public function assert_false($value, $debug = NULL)
  269. {
  270. if ($value != FALSE)
  271. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_false'], gettype($value), var_export($value, TRUE)), $debug);
  272. return $this;
  273. }
  274. public function assert_false_strict($value, $debug = NULL)
  275. {
  276. if ($value !== FALSE)
  277. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_false_strict'], gettype($value), var_export($value, TRUE)), $debug);
  278. return $this;
  279. }
  280. public function assert_equal($expected, $actual, $debug = NULL)
  281. {
  282. if ($expected != $actual)
  283. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_equal'], gettype($expected), var_export($expected, TRUE), gettype($actual), var_export($actual, TRUE)), $debug);
  284. return $this;
  285. }
  286. public function assert_not_equal($expected, $actual, $debug = NULL)
  287. {
  288. if ($expected == $actual)
  289. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_equal'], gettype($expected), var_export($expected, TRUE), gettype($actual), var_export($actual, TRUE)), $debug);
  290. return $this;
  291. }
  292. public function assert_same($expected, $actual, $debug = NULL)
  293. {
  294. if ($expected !== $actual)
  295. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_same'], gettype($expected), var_export($expected, TRUE), gettype($actual), var_export($actual, TRUE)), $debug);
  296. return $this;
  297. }
  298. public function assert_not_same($expected, $actual, $debug = NULL)
  299. {
  300. if ($expected === $actual)
  301. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_same'], gettype($expected), var_export($expected, TRUE), gettype($actual), var_export($actual, TRUE)), $debug);
  302. return $this;
  303. }
  304. public function assert_boolean($value, $debug = NULL)
  305. {
  306. if ( ! is_bool($value))
  307. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_boolean'], gettype($value), var_export($value, TRUE)), $debug);
  308. return $this;
  309. }
  310. public function assert_not_boolean($value, $debug = NULL)
  311. {
  312. if (is_bool($value))
  313. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_boolean'], gettype($value), var_export($value, TRUE)), $debug);
  314. return $this;
  315. }
  316. public function assert_integer($value, $debug = NULL)
  317. {
  318. if ( ! is_int($value))
  319. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_integer'], gettype($value), var_export($value, TRUE)), $debug);
  320. return $this;
  321. }
  322. public function assert_not_integer($value, $debug = NULL)
  323. {
  324. if (is_int($value))
  325. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_integer'], gettype($value), var_export($value, TRUE)), $debug);
  326. return $this;
  327. }
  328. public function assert_float($value, $debug = NULL)
  329. {
  330. if ( ! is_float($value))
  331. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_float'], gettype($value), var_export($value, TRUE)), $debug);
  332. return $this;
  333. }
  334. public function assert_not_float($value, $debug = NULL)
  335. {
  336. if (is_float($value))
  337. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_float'], gettype($value), var_export($value, TRUE)), $debug);
  338. return $this;
  339. }
  340. public function assert_array($value, $debug = NULL)
  341. {
  342. if ( ! is_array($value))
  343. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_array'], gettype($value), var_export($value, TRUE)), $debug);
  344. return $this;
  345. }
  346. public function assert_array_key($key, $array, $debug = NULL)
  347. {
  348. if ( ! array_key_exists($key, $array)) {
  349. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_array_key'], gettype($key), var_export($key, TRUE)), $debug);
  350. }
  351. return $this;
  352. }
  353. public function assert_in_array($value, $array, $debug = NULL)
  354. {
  355. if ( ! in_array($value, $array)) {
  356. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_in_array'], gettype($value), var_export($value, TRUE)), $debug);
  357. }
  358. return $this;
  359. }
  360. public function assert_not_array($value, $debug = NULL)
  361. {
  362. if (is_array($value))
  363. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_array'], gettype($value), var_export($value, TRUE)), $debug);
  364. return $this;
  365. }
  366. public function assert_object($value, $debug = NULL)
  367. {
  368. if ( ! is_object($value))
  369. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_object'], gettype($value), var_export($value, TRUE)), $debug);
  370. return $this;
  371. }
  372. public function assert_not_object($value, $debug = NULL)
  373. {
  374. if (is_object($value))
  375. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_object'], gettype($value), var_export($value, TRUE)), $debug);
  376. return $this;
  377. }
  378. public function assert_null($value, $debug = NULL)
  379. {
  380. if ($value !== NULL)
  381. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_null'], gettype($value), var_export($value, TRUE)), $debug);
  382. return $this;
  383. }
  384. public function assert_not_null($value, $debug = NULL)
  385. {
  386. if ($value === NULL)
  387. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_null'], gettype($value), var_export($value, TRUE)), $debug);
  388. return $this;
  389. }
  390. public function assert_empty($value, $debug = NULL)
  391. {
  392. if ( ! empty($value))
  393. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_empty'], gettype($value), var_export($value, TRUE)), $debug);
  394. return $this;
  395. }
  396. public function assert_not_empty($value, $debug = NULL)
  397. {
  398. if (empty($value))
  399. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_empty'], gettype($value), var_export($value, TRUE)), $debug);
  400. return $this;
  401. }
  402. public function assert_pattern($value, $regex, $debug = NULL)
  403. {
  404. if ( ! is_string($value) OR ! is_string($regex) OR ! preg_match($regex, $value))
  405. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_pattern'], var_export($value, TRUE), var_export($regex, TRUE)), $debug);
  406. return $this;
  407. }
  408. public function assert_not_pattern($value, $regex, $debug = NULL)
  409. {
  410. if ( ! is_string($value) OR ! is_string($regex) OR preg_match($regex, $value))
  411. throw new Kohana_Unit_Test_Exception(sprintf(Unit_Test::$lang['assert_not_pattern'], var_export($value, TRUE), var_export($regex, TRUE)), $debug);
  412. return $this;
  413. }
  414. } // End Unit_Test_Case
  415. class Kohana_Unit_Test_Exception extends Exception {
  416. protected $debug = NULL;
  417. /**
  418. * Sets exception message and debug info.
  419. *
  420. * @param string message
  421. * @param mixed debug info
  422. * @return void
  423. */
  424. public function __construct($message, $debug = NULL)
  425. {
  426. // Failure message
  427. parent::__construct((string) $message);
  428. // Extra user-defined debug info
  429. $this->debug = $debug;
  430. // Overwrite failure location
  431. $trace = $this->getTrace();
  432. $this->file = $trace[0]['file'];
  433. $this->line = $trace[0]['line'];
  434. }
  435. /**
  436. * Returns the user-defined debug info
  437. *
  438. * @return mixed debug property
  439. */
  440. public function getDebug()
  441. {
  442. return $this->debug;
  443. }
  444. } // End Kohana_Unit_Test_Exception