PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Controller/Tester.php

http://github.com/atk4/atk4
PHP | 364 lines | 272 code | 66 blank | 26 comment | 49 complexity | ada745618a8202ea1a2af9bc48e23ff3 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * Tester page is a basic implementation of a testing environment for Agile Toolkit.
  4. * See Documentation for testing.
  5. */
  6. class Controller_Tester extends Page
  7. {
  8. /** @var array */
  9. public $variances = array();
  10. /** @var mixed */
  11. public $input;
  12. /** @var array|string */
  13. public $responses = array();
  14. /** @var bool */
  15. public $auto_test = true;
  16. /** @var Grid $grid */
  17. public $grid;
  18. /** @var Form $form */
  19. public $form;
  20. /** @var int */
  21. public $cnt;
  22. /** Redefine this to the value generated by a test */
  23. public $proper_responses = null;
  24. public function setVariance($arr)
  25. {
  26. $this->variances = $arr;
  27. if (isset($this->grid)) {
  28. foreach ($arr as $key => $item) {
  29. if (is_numeric($key)) {
  30. $key = $item;
  31. }
  32. $this->grid->addColumn('html', $key.'_inf', $key.' info');
  33. $this->grid->addColumn('html,wrap', $key.'_res', $key.' result');
  34. }
  35. }
  36. }
  37. public function init()
  38. {
  39. parent::init();
  40. if (!$this->auto_test) {
  41. $this->setVariance(array('Test'));
  42. return; // used for multi-page testing
  43. }
  44. //$this->grid=$this->add('Grid');
  45. $this->grid->addColumn('template', 'name')
  46. ->setTemplate('<a href="'.$this->app->url(null, array('testonly' => '')).'<?$name?>"><?$name?></a>');
  47. $this->setVariance(array('Test'));
  48. //$this->setVariance(array('GiTemplate','SMlite'));
  49. //$this->runTests();
  50. }
  51. public function skipTests($msg = null)
  52. {
  53. throw $this->exception($msg, 'SkipTests');
  54. }
  55. public function ticker()
  56. {
  57. ++$this->cnt;
  58. }
  59. public function executeTest($test_obj, $test_func, $input)
  60. {
  61. if ($input === null) {
  62. $input = array();
  63. }
  64. return call_user_func_array(array($test_obj, $test_func), $input);
  65. }
  66. public function silentTest($test_obj = null)
  67. {
  68. if (!$test_obj) {
  69. $test_obj = $this;
  70. }
  71. $total = $success = $fail = $exception = 0;
  72. $speed = $memory = 0;
  73. $tested = array();
  74. $failures = array();
  75. foreach (get_class_methods($test_obj) as $method) {
  76. if (strpos($method, 'test_') === 0) {
  77. $m = substr($method, 5);
  78. } elseif (strpos($method, 'prepare_') === 0) {
  79. $m = substr($method, 8);
  80. } else {
  81. continue;
  82. }
  83. if ($tested[$m]) {
  84. continue;
  85. }
  86. $tested[$m] = true;
  87. foreach ($this->variances as $key => $vari) {
  88. if (is_numeric($key)) {
  89. $key = $vari;
  90. }
  91. // Input is a result of preparation function
  92. try {
  93. if (method_exists($test_obj, 'prepare_'.$m)) {
  94. $input = $test_obj->{'prepare_'.$m}($vari, $method);
  95. } else {
  96. if (($test_obj instanceof AbstractObject && $test_obj->hasMethod('prepare'))
  97. || method_exists($test_obj, 'prepare')
  98. ) {
  99. $input = $test_obj->prepare($vari, $method);
  100. } else {
  101. $input = null;
  102. }
  103. }
  104. } catch (Exception $e) {
  105. if ($e instanceof Exception_SkipTests) {
  106. return array(
  107. 'skipped' => $e->getMessage(),
  108. );
  109. }
  110. throw $e;
  111. }
  112. $this->input = $input;
  113. $test_func = method_exists($test_obj, 'test_'.$m) ?
  114. 'test_'.$m : 'test';
  115. ++$total;
  116. $me = memory_get_peak_usage();
  117. $ms = microtime(true);
  118. $this->cnt = 0;
  119. declare (ticks = 1);
  120. register_tick_function(array($this, 'ticker'));
  121. try {
  122. $result = $this->executeTest($test_obj, $test_func, $input);
  123. $ms = microtime(true) - $ms;
  124. $me = ($mend = memory_get_peak_usage()) - $me;
  125. $result = $this->formatResult($row, $key, $result);
  126. $k = $key.'_'.$m;
  127. if ($this->proper_responses[$k] == $result && isset($this->proper_responses[$k])) {
  128. ++$success;
  129. } else {
  130. $failures[] = $method;
  131. ++$fail;
  132. }
  133. } catch (Exception $e) {
  134. if ($e instanceof Exception_SkipTests) {
  135. return array(
  136. 'skipped' => $e->getMessage(),
  137. );
  138. }
  139. ++$exception;
  140. //$ms=microtime(true)-$ms;
  141. $me = ($mend = memory_get_peak_usage()) - $me;
  142. }
  143. unregister_tick_function(array($this, 'ticker'));
  144. $speed += $this->cnt * 1;
  145. $memory += $me;
  146. }
  147. }
  148. return array(
  149. 'total' => $total,
  150. 'failures' => $failures,
  151. 'success' => $success,
  152. 'exception' => $exception,
  153. 'fail' => $fail,
  154. 'speed' => $speed,
  155. 'memory' => $memory,
  156. );
  157. }
  158. public function runTests($test_obj = null)
  159. {
  160. if (!$test_obj) {
  161. $test_obj = $this;
  162. } else {
  163. $this->proper_responses = @$test_obj->proper_responses;
  164. if ($test_obj instanceof AbstractObject) {
  165. $this->add($test_obj);
  166. }
  167. }
  168. $tested = array();
  169. $data = array();
  170. foreach (get_class_methods($test_obj) as $method) {
  171. $m = '';
  172. if (strpos($method, 'test_') === 0) {
  173. $m = substr($method, 5);
  174. } elseif (strpos($method, 'prepare_') === 0) {
  175. $m = substr($method, 8);
  176. } else {
  177. continue;
  178. }
  179. if (isset($_GET['testonly']) && 'test_'.$_GET['testonly'] != $method) {
  180. continue;
  181. }
  182. // Do not retest same function even if it has both prepare and test
  183. if ($tested[$m]) {
  184. continue;
  185. }
  186. $tested[$m] = true;
  187. // Row contains test result data
  188. $row = array('name' => $m, 'id' => $m);
  189. foreach ($this->variances as $key => $vari) {
  190. if (is_numeric($key)) {
  191. $key = $vari;
  192. }
  193. try {
  194. // Input is a result of preparation function
  195. if (method_exists($test_obj, 'prepare_'.$m)) {
  196. $input = $test_obj->{'prepare_'.$m}($vari, $method);
  197. } else {
  198. if (($test_obj instanceof AbstractObject && $test_obj->hasMethod('prepare'))
  199. || method_exists($test_obj, 'prepare')
  200. ) {
  201. $input = $test_obj->prepare($vari, $method);
  202. } else {
  203. $input = null;
  204. }
  205. }
  206. } catch (Exception $e) {
  207. if ($e instanceof Exception_SkipTests) {
  208. $this->grid->destroy();
  209. /** @type View_Error $v */
  210. $v = $this->add('View_Error');
  211. $v->set('Skipping all tests: '.$e->getMessage());
  212. return;
  213. }
  214. throw $e;
  215. }
  216. $this->input = $input;
  217. $test_func = method_exists($test_obj, 'test_'.$m) ?
  218. 'test_'.$m : 'test';
  219. // Test speed
  220. $me = memory_get_peak_usage();
  221. $ms = microtime(true);
  222. $this->cnt = 0;
  223. declare (ticks = 1);
  224. register_tick_function(array($this, 'ticker'));
  225. try {
  226. //$result=$test_obj->$test_func($input[0],$input[1],$input[2]);
  227. $result = $this->executeTest($test_obj, $test_func, $input);
  228. } catch (Exception $e) {
  229. if ($e instanceof Exception_SkipTests) {
  230. $this->grid->destroy();
  231. /** @type View_Error $v */
  232. $v = $this->add('View_Error');
  233. $v->set('Skipping all tests: '.$e->getMessage());
  234. }
  235. if ($_GET['tester_details'] == $row['name'] && $_GET['vari'] == $vari) {
  236. throw $e;
  237. }
  238. $result = 'Exception: '.($e instanceof BaseException ? $e->getText() : $e->getMessage());
  239. /** @type P $ll */
  240. $ll = $this->add('P', $row['name']);
  241. /** @type View $v */
  242. $v = $ll->add('View');
  243. $v->setElement('a')
  244. ->setAttr('href', '#')
  245. ->set('More details')
  246. ->js('click')->univ()->frameURL(
  247. 'Exception Details for test '.$row['name'],
  248. $this->app->url(null, array('tester_details' => $row['name'], 'vari' => $vari))
  249. );
  250. $result .= $ll->getHTML();
  251. }
  252. $ms = microtime(true) - $ms;
  253. $me = ($mend = memory_get_peak_usage()) - $me;
  254. unregister_tick_function(array($this, 'ticker'));
  255. $row[$key.'_inf'] = 'Ticks: '.($this->cnt * 1).'<br/>Memory: '.$me;
  256. $result = $this->formatResult($row, $key, $result);
  257. $k = $key.'_'.$row['name'];
  258. if ($this->proper_responses[$k] == $result && isset($this->proper_responses[$k])) {
  259. $row[$key.'_res'] = '<font color="green">PASS</font><br/>'.htmlspecialchars($result);
  260. } elseif (isset($this->proper_responses[$k])) {
  261. $row[$key.'_res'] = '<font color="red">'.htmlspecialchars($result).'</font><br/>'.
  262. var_export($this->proper_responses[$k], true);
  263. }
  264. $this->responses[] = '"'.$k.'"'.'=>'.var_export($result, true);
  265. }
  266. $data[] = $row;
  267. }
  268. $this->grid->setSource($data);
  269. if (!$_GET['testonly']) {
  270. $f = $this->form;
  271. $ff = $f->addField('Text', 'responses');
  272. $this->responses =
  273. ' public $proper_responses=array(
  274. '.implode(',
  275. ', $this->responses).'
  276. );';
  277. $ff->set($this->responses);
  278. $ff->js('click')->select();
  279. }
  280. }
  281. public function formatResult(&$row, $key, $result)
  282. {
  283. $row[$key.'_res'] = $result;
  284. return (string) $result;
  285. }
  286. public function expect($value, $expectation)
  287. {
  288. return $value == $expectation ? 'OK' : 'ERR';
  289. }
  290. public function _prepare($t, $str)
  291. {
  292. $result = '';
  293. for ($i = 0; $i < 100; ++$i) {
  294. $result .= $str;
  295. }
  296. return array($this->add($t), $result);
  297. }
  298. }