PageRenderTime 68ms CodeModel.GetById 40ms RepoModel.GetById 1ms app.codeStats 0ms

/bdd/ArrBDD.php

https://github.com/darkredz/ArrBDD
PHP | 267 lines | 189 code | 38 blank | 40 comment | 42 complexity | ca3150dff5d7f35584907c4d4d3225bb MD5 | raw file
  1. <?php
  2. /**
  3. * ArrBDD class file.
  4. *
  5. * @author Leng Sheng Hong <darkredz@gmail.com>
  6. * @link http://www.doophp.com/arr-bdd
  7. * @copyright Copyright &copy; 2011 Leng Sheng Hong
  8. * @license http://www.doophp.com/license
  9. * @since 0.1
  10. */
  11. /**
  12. * ArrBDD - a simple BDD library utilizing PHP associative arrays and closures
  13. *
  14. * @author Leng Sheng Hong <darkredz@gmail.com>
  15. * @since 0.1
  16. */
  17. class ArrBDD{
  18. protected $assertErrorKey;
  19. protected $assertError;
  20. protected $assertFailMsg = array();
  21. const SUBJECT_VAR_DUMP = 'var_dump';
  22. const SUBJECT_PRINT_R = 'print_r';
  23. const SUBJECT_VAR_EXPORT = 'var_export';
  24. public $subjectView;
  25. public function __construct($subjectView = ArrBDD::SUBJECT_VAR_DUMP){
  26. assert_options(ASSERT_CALLBACK, array(&$this, 'onAssertFail'));
  27. assert_options(ASSERT_WARNING, 0);
  28. $this->subjectView = $subjectView;
  29. }
  30. protected function exportSubject($subject){
  31. switch($this->subjectView){
  32. case ArrBDD::SUBJECT_VAR_DUMP:
  33. var_dump($subject);
  34. break;
  35. case ArrBDD::SUBJECT_PRINT_R:
  36. print_r($subject);
  37. break;
  38. case ArrBDD::SUBJECT_VAR_EXPORT:
  39. var_export($subject, true);
  40. break;
  41. }
  42. }
  43. public function onAssertFail($file, $line, $expr) {
  44. if( empty($expr) )
  45. $this->assertError = "Assertion failed in $file on line $line";
  46. else
  47. $this->assertError = "Assertion failed in $file on line $line: $expr";
  48. //print "<br/>[$this->assertErrorKey] \n\t$this->assertError\n<br/>";
  49. //print "<br/>$this->assertError<br/>";
  50. if( is_array($this->assertErrorKey) ){
  51. if( empty($this->assertFailMsg[$this->assertErrorKey[0]][$this->assertErrorKey[1]]) ){
  52. $this->assertFailMsg[$this->assertErrorKey[0]][$this->assertErrorKey[1]] = array();
  53. }
  54. $this->assertFailMsg[$this->assertErrorKey[0]][$this->assertErrorKey[1]][] = $this->assertError;
  55. }
  56. else{
  57. if( empty($this->assertFailMsg[$this->assertErrorKey]) ){
  58. $this->assertFailMsg[$this->assertErrorKey] = array();
  59. }
  60. $this->assertFailMsg[$this->assertErrorKey][] = $this->assertError;
  61. }
  62. $this->assertError = array( $this->assertError );
  63. }
  64. public function run($specs, $includeSubject=false){
  65. $testResults = array();
  66. foreach($specs as $specName => $spec){
  67. $results = array();
  68. $subject = null;
  69. // Subject can be a closure or the actual value
  70. if( isset( $spec['subject'] ) ){
  71. $sbj = $spec['subject'];
  72. if(is_callable($sbj))
  73. $subject = $sbj();
  74. else
  75. $subject = $sbj;
  76. }
  77. // include subject to the result
  78. if( $includeSubject ){
  79. ob_start();
  80. $this->exportSubject($subject);
  81. $content = ob_get_contents();
  82. ob_end_clean();
  83. $results['subject'] = $content;
  84. }
  85. foreach( $spec as $stepName => $step ){
  86. if($stepName=='subject') continue;
  87. $this->assertErrorKey = $stepName;
  88. // not a WHEN
  89. if( is_callable($step) ){
  90. $rs = $step($subject);
  91. // $results[$stepName] = ($rs) ? $rs : $this->assertError;
  92. $this->evalAsserts($results, $rs, $stepName);
  93. }
  94. // a WHEN
  95. else if( is_array($step) ){
  96. $_subject = null;
  97. // get inner step's subject, pass main step subject and inner subject to THEN closure
  98. if( isset( $step['subject'] ) ){
  99. $sbj = $step['subject'];
  100. // Need passing back the main subject to the inner step subject closure
  101. if(is_callable($sbj))
  102. $_subject = $sbj($subject);
  103. else
  104. $_subject = $sbj;
  105. }
  106. // include subject to the result
  107. if( $includeSubject ){
  108. ob_start();
  109. $this->exportSubject($_subject);
  110. $_content = ob_get_contents();
  111. ob_end_clean();
  112. $results[$stepName]['subject'] = $_content;
  113. }
  114. foreach( $step as $_stepName => $_step ){
  115. if($_stepName=='subject') continue;
  116. $this->assertErrorKey = array($stepName, $_stepName);
  117. $rs = $_step($_subject, $subject);
  118. $this->evalAsserts($results, $rs, $stepName, $_stepName);
  119. }
  120. }
  121. }
  122. $testResults[$specName] = $results;
  123. }
  124. return $testResults;
  125. }
  126. protected function evalAsserts(&$results, &$rs, $stepName, $_stepName = NULL){
  127. // if an array is returned, check if the first value(assertion value) pass the test
  128. if( is_array($rs) ){
  129. //====== single assertion =====
  130. if( $rs[0]===true ){
  131. $rs = $rs[0];
  132. }
  133. // if fail, then use the assertion failed msg provided, if available
  134. else if( !empty($rs[1]) && is_string($rs[1]) ){
  135. $err = $rs[1];
  136. $this->assertError = array($err);
  137. $rs = false; // failed
  138. }
  139. // Single assertion, if fail, and no debug msg specify, use default assertion error msg
  140. else if( empty($rs[1]) && empty($rs[0][1]) ){
  141. $rs = false;
  142. }
  143. //====== multiple assertion =====
  144. else if( is_array($rs[0]) ){
  145. $asserts = $rs;
  146. // multiple assertion, get the error debug msg if available, eg. array( expr, "msg on the test" )
  147. // $assert[0] = expr, $assert[1] = msg
  148. $rs = array();
  149. foreach( $asserts as $assert ){
  150. # var_dump($assert);
  151. if( $assert[0]!==true ){
  152. if( !empty($assert[1]) ){
  153. $rs[] = $assert[1];
  154. }
  155. else{
  156. $rs[] = false;//$this->assertError[0];
  157. }
  158. }
  159. else{
  160. $rs[] = true;
  161. }
  162. }
  163. }
  164. }
  165. // assign result/fail msg for the steps (inner step, if inner is set)
  166. // if test passed, use boolean true, else if failed use the assertion error message
  167. if( isset($_stepName) ){
  168. $rst = &$results[$stepName][$_stepName];
  169. if(!empty($this->assertFailMsg[$stepName][$_stepName]))
  170. $afMsg = $this->assertFailMsg[$stepName][$_stepName];
  171. }
  172. else{
  173. $rst = &$results[$stepName];
  174. if(!empty($this->assertFailMsg[$stepName]))
  175. $afMsg = $this->assertFailMsg[$stepName];
  176. }
  177. if( empty($afMsg) ){
  178. if($this->assertError===null) $this->assertError = false;
  179. $rst = ($rs) ? $rs : $this->assertError;
  180. }
  181. else if(!empty($rs)){
  182. $this->assertError = $afMsg;
  183. $i = 0;
  184. foreach( $rs as &$rsvalue){
  185. if($rsvalue===true) continue;
  186. if($rsvalue===false)
  187. $rsvalue = $this->assertError[$i];
  188. else
  189. $rsvalue = $this->assertError[$i] . ': '. $rsvalue;
  190. $i++;
  191. }
  192. $rst = $rs;
  193. }
  194. else{
  195. if(is_array($this->assertError) && sizeof($this->assertError)===1){
  196. $rst = $this->assertError[0];
  197. if(isset($afMsg[0]) && strpos($rst, 'Assertion failed in ')!==0){
  198. $rst = $afMsg[0] . ': ' . $rst;
  199. }
  200. }
  201. else{
  202. $rst = $this->assertError;
  203. }
  204. }
  205. //errors will always be an array.
  206. if($rst!==true && !is_array($rst)){
  207. $rst = array($rst);
  208. }
  209. //var_dump($rst);
  210. $this->assertError = null;
  211. }
  212. //echo "\n============= Test Results ================\n";
  213. //print_r( arrBDD($specs) );
  214. //echo "\n\n\n\n\n\n";
  215. public function outputPre( $result ){
  216. echo '<pre>';
  217. print_r( $result );
  218. }
  219. public function outputVardump( $result ){
  220. echo '<pre>';
  221. var_dump( $result );
  222. }
  223. public function outputJSON( $result ){
  224. header('Cache-Control: no-cache, must-revalidate');
  225. header('Expires: Mon, 26 Jul 1970 05:00:00 GMT');
  226. header('Content-type: application/json');
  227. echo json_encode( $result );
  228. }
  229. }