You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

406 lines
8.8 KiB

7 years ago
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.3.1
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * Unit Testing Class
  41. *
  42. * Simple testing class
  43. *
  44. * @package CodeIgniter
  45. * @subpackage Libraries
  46. * @category UnitTesting
  47. * @author EllisLab Dev Team
  48. * @link https://codeigniter.com/user_guide/libraries/unit_testing.html
  49. */
  50. class CI_Unit_test {
  51. /**
  52. * Active flag
  53. *
  54. * @var bool
  55. */
  56. public $active = TRUE;
  57. /**
  58. * Test results
  59. *
  60. * @var array
  61. */
  62. public $results = array();
  63. /**
  64. * Strict comparison flag
  65. *
  66. * Whether to use === or == when comparing
  67. *
  68. * @var bool
  69. */
  70. public $strict = FALSE;
  71. /**
  72. * Template
  73. *
  74. * @var string
  75. */
  76. protected $_template = NULL;
  77. /**
  78. * Template rows
  79. *
  80. * @var string
  81. */
  82. protected $_template_rows = NULL;
  83. /**
  84. * List of visible test items
  85. *
  86. * @var array
  87. */
  88. protected $_test_items_visible = array(
  89. 'test_name',
  90. 'test_datatype',
  91. 'res_datatype',
  92. 'result',
  93. 'file',
  94. 'line',
  95. 'notes'
  96. );
  97. // --------------------------------------------------------------------
  98. /**
  99. * Constructor
  100. *
  101. * @return void
  102. */
  103. public function __construct()
  104. {
  105. log_message('info', 'Unit Testing Class Initialized');
  106. }
  107. // --------------------------------------------------------------------
  108. /**
  109. * Run the tests
  110. *
  111. * Runs the supplied tests
  112. *
  113. * @param array $items
  114. * @return void
  115. */
  116. public function set_test_items($items)
  117. {
  118. if ( ! empty($items) && is_array($items))
  119. {
  120. $this->_test_items_visible = $items;
  121. }
  122. }
  123. // --------------------------------------------------------------------
  124. /**
  125. * Run the tests
  126. *
  127. * Runs the supplied tests
  128. *
  129. * @param mixed $test
  130. * @param mixed $expected
  131. * @param string $test_name
  132. * @param string $notes
  133. * @return string
  134. */
  135. public function run($test, $expected = TRUE, $test_name = 'undefined', $notes = '')
  136. {
  137. if ($this->active === FALSE)
  138. {
  139. return FALSE;
  140. }
  141. if (in_array($expected, array('is_object', 'is_string', 'is_bool', 'is_true', 'is_false', 'is_int', 'is_numeric', 'is_float', 'is_double', 'is_array', 'is_null', 'is_resource'), TRUE))
  142. {
  143. $result = $expected($test);
  144. $extype = str_replace(array('true', 'false'), 'bool', str_replace('is_', '', $expected));
  145. }
  146. else
  147. {
  148. $result = ($this->strict === TRUE) ? ($test === $expected) : ($test == $expected);
  149. $extype = gettype($expected);
  150. }
  151. $back = $this->_backtrace();
  152. $report = array (
  153. 'test_name' => $test_name,
  154. 'test_datatype' => gettype($test),
  155. 'res_datatype' => $extype,
  156. 'result' => ($result === TRUE) ? 'passed' : 'failed',
  157. 'file' => $back['file'],
  158. 'line' => $back['line'],
  159. 'notes' => $notes
  160. );
  161. $this->results[] = $report;
  162. return $this->report($this->result(array($report)));
  163. }
  164. // --------------------------------------------------------------------
  165. /**
  166. * Generate a report
  167. *
  168. * Displays a table with the test data
  169. *
  170. * @param array $result
  171. * @return string
  172. */
  173. public function report($result = array())
  174. {
  175. if (count($result) === 0)
  176. {
  177. $result = $this->result();
  178. }
  179. $CI =& get_instance();
  180. $CI->load->language('unit_test');
  181. $this->_parse_template();
  182. $r = '';
  183. foreach ($result as $res)
  184. {
  185. $table = '';
  186. foreach ($res as $key => $val)
  187. {
  188. if ($key === $CI->lang->line('ut_result'))
  189. {
  190. if ($val === $CI->lang->line('ut_passed'))
  191. {
  192. $val = '<span style="color: #0C0;">'.$val.'</span>';
  193. }
  194. elseif ($val === $CI->lang->line('ut_failed'))
  195. {
  196. $val = '<span style="color: #C00;">'.$val.'</span>';
  197. }
  198. }
  199. $table .= str_replace(array('{item}', '{result}'), array($key, $val), $this->_template_rows);
  200. }
  201. $r .= str_replace('{rows}', $table, $this->_template);
  202. }
  203. return $r;
  204. }
  205. // --------------------------------------------------------------------
  206. /**
  207. * Use strict comparison
  208. *
  209. * Causes the evaluation to use === rather than ==
  210. *
  211. * @param bool $state
  212. * @return void
  213. */
  214. public function use_strict($state = TRUE)
  215. {
  216. $this->strict = (bool) $state;
  217. }
  218. // --------------------------------------------------------------------
  219. /**
  220. * Make Unit testing active
  221. *
  222. * Enables/disables unit testing
  223. *
  224. * @param bool
  225. * @return void
  226. */
  227. public function active($state = TRUE)
  228. {
  229. $this->active = (bool) $state;
  230. }
  231. // --------------------------------------------------------------------
  232. /**
  233. * Result Array
  234. *
  235. * Returns the raw result data
  236. *
  237. * @param array $results
  238. * @return array
  239. */
  240. public function result($results = array())
  241. {
  242. $CI =& get_instance();
  243. $CI->load->language('unit_test');
  244. if (count($results) === 0)
  245. {
  246. $results = $this->results;
  247. }
  248. $retval = array();
  249. foreach ($results as $result)
  250. {
  251. $temp = array();
  252. foreach ($result as $key => $val)
  253. {
  254. if ( ! in_array($key, $this->_test_items_visible))
  255. {
  256. continue;
  257. }
  258. elseif (in_array($key, array('test_name', 'test_datatype', 'res_datatype', 'result'), TRUE))
  259. {
  260. if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val), FALSE)))
  261. {
  262. $val = $line;
  263. }
  264. }
  265. $temp[$CI->lang->line('ut_'.$key, FALSE)] = $val;
  266. }
  267. $retval[] = $temp;
  268. }
  269. return $retval;
  270. }
  271. // --------------------------------------------------------------------
  272. /**
  273. * Set the template
  274. *
  275. * This lets us set the template to be used to display results
  276. *
  277. * @param string
  278. * @return void
  279. */
  280. public function set_template($template)
  281. {
  282. $this->_template = $template;
  283. }
  284. // --------------------------------------------------------------------
  285. /**
  286. * Generate a backtrace
  287. *
  288. * This lets us show file names and line numbers
  289. *
  290. * @return array
  291. */
  292. protected function _backtrace()
  293. {
  294. $back = debug_backtrace();
  295. return array(
  296. 'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''),
  297. 'line' => (isset($back[1]['line']) ? $back[1]['line'] : '')
  298. );
  299. }
  300. // --------------------------------------------------------------------
  301. /**
  302. * Get Default Template
  303. *
  304. * @return string
  305. */
  306. protected function _default_template()
  307. {
  308. $this->_template = "\n".'<table style="width:100%; font-size:small; margin:10px 0; border-collapse:collapse; border:1px solid #CCC;">{rows}'."\n</table>";
  309. $this->_template_rows = "\n\t<tr>\n\t\t".'<th style="text-align: left; border-bottom:1px solid #CCC;">{item}</th>'
  310. ."\n\t\t".'<td style="border-bottom:1px solid #CCC;">{result}</td>'."\n\t</tr>";
  311. }
  312. // --------------------------------------------------------------------
  313. /**
  314. * Parse Template
  315. *
  316. * Harvests the data within the template {pseudo-variables}
  317. *
  318. * @return void
  319. */
  320. protected function _parse_template()
  321. {
  322. if ($this->_template_rows !== NULL)
  323. {
  324. return;
  325. }
  326. if ($this->_template === NULL OR ! preg_match('/\{rows\}(.*?)\{\/rows\}/si', $this->_template, $match))
  327. {
  328. $this->_default_template();
  329. return;
  330. }
  331. $this->_template_rows = $match[1];
  332. $this->_template = str_replace($match[0], '{rows}', $this->_template);
  333. }
  334. }
  335. /**
  336. * Helper function to test boolean TRUE
  337. *
  338. * @param mixed $test
  339. * @return bool
  340. */
  341. function is_true($test)
  342. {
  343. return ($test === TRUE);
  344. }
  345. /**
  346. * Helper function to test boolean FALSE
  347. *
  348. * @param mixed $test
  349. * @return bool
  350. */
  351. function is_false($test)
  352. {
  353. return ($test === FALSE);
  354. }