PageRenderTime 75ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/spec/spec.php

http://github.com/speedmax/h2o-php
PHP | 324 lines | 276 code | 11 blank | 37 comment | 7 complexity | b00bf77380613503e2de420a406d6a1d MD5 | raw file
  1. <?php
  2. /**
  3. * @name SimpleSpec
  4. * PHP SimpleTest extension for Behavior driven development(BDD)
  5. *
  6. * why not PHPSpec? well its a good project but SimpleTest has better coverage for testing
  7. * and i want better grammer
  8. *
  9. * Features:
  10. * - Reuse SimpleTest framework
  11. * - simplly one include from away
  12. * - Underscore for readibility - all examples uses underscore to seperate descriptions.
  13. * - Natural language grammer
  14. * - before_all, after_all is not supported, i don't want to modify SimpleTest
  15. * - conventional before/after named prepare/cleanup respectively
  16. *
  17. * @example
  18. * class Describe_his_mum extends SimpleSpec {
  19. * function prepare() {
  20. * $this->mum = new Mum(array('mood'=>'angry'));
  21. * }
  22. *
  23. * function should_be_very_angry_when_i_break_my_lunch_box() {
  24. * expects($this->mum->mood)->should_be('angry');
  25. * }
  26. *
  27. * function should_be_very_happy_when_i_punch_her_in_the_face() {
  28. * punch($this->mum);
  29. * expects($this->mum->mood)->should_be('happy');
  30. * }
  31. *
  32. * function cleanup() {
  33. * unset($this->mum); // kill da mum
  34. * }
  35. * }
  36. * @author - Taylor Luk aka 'speedmax'
  37. * @license Free for all
  38. */
  39. class SimpleSpec extends UnitTestCase {
  40. public $target;
  41. private $negate;
  42. private $matcher;
  43. function __construct($label = false) {
  44. if (! $label) {
  45. $label = str_replace(array('Describe_', '_'), array('', ' '), get_class($this));
  46. }
  47. $this->matcher = new SpecMatcher($this);
  48. parent::__construct($label);
  49. }
  50. function _isTest($method) {
  51. if (strtolower(substr($method, 0, 2)) == 'it' || strtolower(substr($method, 0, 6)) == 'should') {
  52. return ! SimpleTestCompatibility::isA($this, strtolower($method));
  53. }
  54. return false;
  55. }
  56. function prepare() {
  57. }
  58. function cleanup() {
  59. }
  60. function setUp() {
  61. $this->prepare();
  62. }
  63. function tearDown() {
  64. $this->cleanup();
  65. }
  66. function __call($name, $args) {
  67. $matcher = null;
  68. $this->matcher->negate(false);
  69. array_unshift($args, $this->target);
  70. if (preg_match('/should_not_(.*)/', $name, $match)) {
  71. $matcher = $match[1];
  72. $this->matcher->negate(true);
  73. }
  74. elseif (preg_match('/should_(.*)/', $name, $match)) {
  75. $matcher = $match[1];
  76. }
  77. if (!method_exists($this->matcher, $matcher)) {
  78. throw new Exception("matcher doesn't exist");
  79. } else {
  80. call_user_func_array(array($this->matcher, $matcher), $args);
  81. }
  82. }
  83. function offsetGet($object) {
  84. return $this->expect($object);
  85. }
  86. function offsetSet($key, $value) {}
  87. function offsetExists($key) {}
  88. function offsetUnset($key) {}
  89. function expect($object) {
  90. $this->target = $object;
  91. return $this;
  92. }
  93. function value_of($object) {
  94. return $this->expect($object);
  95. }
  96. function assert(&$expectation, $compare, $message = '%s') {
  97. $result = $expectation->test($compare);
  98. if ($this->matcher->negate) {
  99. $result = !$result;
  100. }
  101. if ($result) {
  102. return $this->pass(sprintf($message,$expectation->overlayMessage($compare, $this->_reporter->getDumper())));
  103. } else {
  104. return $this->fail(sprintf($message,$expectation->overlayMessage($compare, $this->_reporter->getDumper())));
  105. }
  106. }
  107. /**
  108. * Uses a stack trace to find the line of an assertion.
  109. * @return string Line number of first assert*
  110. * method embedded in format string.
  111. * @access public
  112. */
  113. function getAssertionLine() {
  114. $trace = new SimpleStackTrace(array('should', 'it_should', 'assert', 'expect', 'pass', 'fail', 'skip'));
  115. return $trace->traceMethod();
  116. }
  117. }
  118. function expects($subject) {
  119. $trace = debug_backtrace();
  120. $object = $trace[1]['object'];
  121. return $object->expect($subject);
  122. }
  123. class Have_Matcher {
  124. function __construct($subject, $count, $runtime) {
  125. $this->subject = $subject;
  126. $this->count = $count;
  127. $this->runtime = $this->runtime;
  128. }
  129. function __get($key) {
  130. $object = $runtime->target;
  131. if (is_array($object) && isset($object[$this->subject]))
  132. $subject = $object[$this->subject];
  133. elseif (is_object($object) && isset($object->{$this->subject}))
  134. $subject = $object->{$this->subject};
  135. return $this->runtime->be(count($subject), $this->count);
  136. }
  137. }
  138. class SpecMatcher {
  139. private $tester;
  140. public $negate;
  141. function __construct($runtime) {
  142. $this->runtime = $runtime;
  143. }
  144. function negate($bool = false) {
  145. $this->negate = $bool;
  146. }
  147. function be($first, $second, $message = '%s') {
  148. return $this->runtime->assert(new EqualExpectation($first), $second, $message);
  149. }
  150. function be_equal($first, $second, $message = '%s') {
  151. return $this->be($first, $second, $message);
  152. }
  153. function be_empty($subject, $message = '%s') {
  154. $dumper = new SimpleDumper();
  155. return $this->be_true(empty($subject) == true, "[{$dumper->describeValue($subject)}] should be empty");
  156. }
  157. function be_true($result, $message = '%s') {
  158. return $this->runtime->assert(new TrueExpectation(), $result, $message);
  159. }
  160. function be_false($result, $message = '%s') {
  161. return $this->runtime->assert(new FalseExpectation(), $result, $message);
  162. }
  163. function be_null($value, $message = '%s') {
  164. $dumper = new SimpleDumper();
  165. $message = sprintf($message, '[' . $dumper->describeValue($value) . '] should be null');
  166. return $this->runtime->assert(new TrueExpectation(), ! isset($value), $message);
  167. }
  168. function be_a($object, $type, $message = '%s') {
  169. if (strtolower($type) == 'object')
  170. $type = 'stdClass';
  171. return $this->runtime->assert(new IsAExpectation($type),$object, $message);
  172. }
  173. function be_an($object, $type, $message = '%s') {
  174. return $this->be_a($object, $type, $message);
  175. }
  176. function be_within_margin($first, $second, $margin, $message = '%s') {
  177. return $this->runtime->assert(
  178. new WithinMarginExpectation($first, $margin),
  179. $second,
  180. $message);
  181. }
  182. function be_outside_margin($first, $second, $margin, $message = '%s') {
  183. return $this->runtime->assert(
  184. new assertOutsideMargin($first, $margin),
  185. $second,
  186. $message);
  187. }
  188. function be_identical($first, $second, $message = '%s') {
  189. return $this->runtime->assert(
  190. new IdenticalExpectation($first),
  191. $second,
  192. $message);
  193. }
  194. function be_reference_of(&$first, &$second, $message = '%s') {
  195. $dumper = new SimpleDumper();
  196. $message = sprintf(
  197. $message,
  198. '[' . $dumper->describeValue($first) .
  199. '] and [' . $dumper->describeValue($second) .
  200. '] should reference the same object');
  201. return $this->runtime->assert(new TrueExpectation(), SimpleTestCompatibility::isReference($first, $second), $message);
  202. }
  203. function be_clone_of(&$first, &$second, $message = '%s') {
  204. $dumper = new SimpleDumper();
  205. $message = sprintf(
  206. $message,
  207. '[' . $dumper->describeValue($first) .
  208. '] and [' . $dumper->describeValue($second) .
  209. '] should not be the same object');
  210. $identical = new IdenticalExpectation($first);
  211. return $this->runtime->assert(new TrueExpectation(),
  212. $identical->test($second) && ! SimpleTestCompatibility::isReference($first, $second),
  213. $message);
  214. }
  215. function be_copy_of(&$first, &$second, $message = '%s') {
  216. $dumper = new SimpleDumper();
  217. $message = sprintf(
  218. $message,
  219. "[" . $dumper->describeValue($first) .
  220. "] and [" . $dumper->describeValue($second) .
  221. "] should not be the same object");
  222. return $this->runtime->assert(new FaseExpectation(),
  223. SimpleTestCompatibility::isReference($first, $second),
  224. $message);
  225. }
  226. function contain($subject, $target, $message = '%s') {
  227. $dumper = new SimpleDumper();
  228. $message = "[ {$dumper->describeValue($subject)}] should contain [{$dumper->describeValue($target)}]";
  229. if (is_array($subject) && is_array($target)) {
  230. return $this->be_true(array_intersect($target, $subject) == $target, $message);
  231. } elseif (is_array($subject)) {
  232. return $this->be_true(in_array($target, $subject), $message);
  233. } elseif (is_string($subject)) {
  234. return $this->be_true(strpos($target, $subject) !== false, $message);
  235. }
  236. }
  237. function have($target, $count, $key, $messages = '%s') {
  238. $dumper = new SimpleDumper();
  239. $subject = null;
  240. if (is_array($target) && isset($target[$key]))
  241. $subject = $target[$key];
  242. elseif (is_object($target) && isset($target->$key))
  243. $subject = $target->$key;
  244. $result = count($subject);
  245. $messages = "Expecting count for [$key] should be [$count], got [$result]";
  246. return $this->be($result, $count, $messages);
  247. }
  248. function match($subject, $pattern, $message = '%s') {
  249. $regex = "/^[\/{#](.*)[\/}#][imsxeADSUXJu]*/sm";
  250. if (preg_match($regex, $subject)) {
  251. list($subject, $pattern) = array($pattern, $subject);
  252. }
  253. return $this->runtime->assert(
  254. new PatternExpectation($pattern),
  255. $subject,
  256. $message);
  257. }
  258. function expect_error($message = '%s') {
  259. $context = &SimpleTest::getContext();
  260. $queue = &$context->get('SimpleErrorQueue');
  261. $queue->expectError($this->runtime->_coerceExpectation($this->negate), $message);
  262. }
  263. function expect_exception($message = '%s') {
  264. $context = &SimpleTest::getContext();
  265. $queue = &$context->get('SimpleExceptionTrap');
  266. // :HACK: Directly substituting in seems to cause a segfault with
  267. // Zend Optimizer on some systems
  268. $line = $this->runtime->getAssertionLine();
  269. $queue->expectException($this->negate, $message . $line);
  270. }
  271. }
  272. ?>