PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Page/Tester.php

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