/spec/spec.php
PHP | 324 lines | 276 code | 11 blank | 37 comment | 7 complexity | b00bf77380613503e2de420a406d6a1d MD5 | raw file
- <?php
- /**
- * @name SimpleSpec
- * PHP SimpleTest extension for Behavior driven development(BDD)
- *
- * why not PHPSpec? well its a good project but SimpleTest has better coverage for testing
- * and i want better grammer
- *
- * Features:
- * - Reuse SimpleTest framework
- * - simplly one include from away
- * - Underscore for readibility - all examples uses underscore to seperate descriptions.
- * - Natural language grammer
- * - before_all, after_all is not supported, i don't want to modify SimpleTest
- * - conventional before/after named prepare/cleanup respectively
- *
- * @example
- * class Describe_his_mum extends SimpleSpec {
- * function prepare() {
- * $this->mum = new Mum(array('mood'=>'angry'));
- * }
- *
- * function should_be_very_angry_when_i_break_my_lunch_box() {
- * expects($this->mum->mood)->should_be('angry');
- * }
- *
- * function should_be_very_happy_when_i_punch_her_in_the_face() {
- * punch($this->mum);
- * expects($this->mum->mood)->should_be('happy');
- * }
- *
- * function cleanup() {
- * unset($this->mum); // kill da mum
- * }
- * }
- * @author - Taylor Luk aka 'speedmax'
- * @license Free for all
- */
-
- class SimpleSpec extends UnitTestCase {
- public $target;
- private $negate;
- private $matcher;
-
- function __construct($label = false) {
- if (! $label) {
- $label = str_replace(array('Describe_', '_'), array('', ' '), get_class($this));
- }
- $this->matcher = new SpecMatcher($this);
- parent::__construct($label);
- }
-
- function _isTest($method) {
- if (strtolower(substr($method, 0, 2)) == 'it' || strtolower(substr($method, 0, 6)) == 'should') {
- return ! SimpleTestCompatibility::isA($this, strtolower($method));
- }
- return false;
- }
-
- function prepare() {
- }
-
-
- function cleanup() {
- }
-
- function setUp() {
- $this->prepare();
- }
-
- function tearDown() {
- $this->cleanup();
- }
-
- function __call($name, $args) {
- $matcher = null;
- $this->matcher->negate(false);
- array_unshift($args, $this->target);
-
- if (preg_match('/should_not_(.*)/', $name, $match)) {
- $matcher = $match[1];
- $this->matcher->negate(true);
- }
- elseif (preg_match('/should_(.*)/', $name, $match)) {
- $matcher = $match[1];
- }
-
- if (!method_exists($this->matcher, $matcher)) {
- throw new Exception("matcher doesn't exist");
- } else {
- call_user_func_array(array($this->matcher, $matcher), $args);
- }
- }
-
- function offsetGet($object) {
- return $this->expect($object);
- }
-
- function offsetSet($key, $value) {}
- function offsetExists($key) {}
- function offsetUnset($key) {}
-
- function expect($object) {
- $this->target = $object;
- return $this;
- }
-
- function value_of($object) {
- return $this->expect($object);
- }
-
- function assert(&$expectation, $compare, $message = '%s') {
- $result = $expectation->test($compare);
- if ($this->matcher->negate) {
- $result = !$result;
- }
- if ($result) {
- return $this->pass(sprintf($message,$expectation->overlayMessage($compare, $this->_reporter->getDumper())));
- } else {
- return $this->fail(sprintf($message,$expectation->overlayMessage($compare, $this->_reporter->getDumper())));
- }
- }
-
- /**
- * Uses a stack trace to find the line of an assertion.
- * @return string Line number of first assert*
- * method embedded in format string.
- * @access public
- */
- function getAssertionLine() {
- $trace = new SimpleStackTrace(array('should', 'it_should', 'assert', 'expect', 'pass', 'fail', 'skip'));
- return $trace->traceMethod();
- }
- }
-
- function expects($subject) {
- $trace = debug_backtrace();
- $object = $trace[1]['object'];
- return $object->expect($subject);
- }
-
- class Have_Matcher {
- function __construct($subject, $count, $runtime) {
- $this->subject = $subject;
- $this->count = $count;
- $this->runtime = $this->runtime;
- }
-
- function __get($key) {
- $object = $runtime->target;
-
- if (is_array($object) && isset($object[$this->subject]))
- $subject = $object[$this->subject];
- elseif (is_object($object) && isset($object->{$this->subject}))
- $subject = $object->{$this->subject};
- return $this->runtime->be(count($subject), $this->count);
- }
- }
-
- class SpecMatcher {
- private $tester;
- public $negate;
-
- function __construct($runtime) {
- $this->runtime = $runtime;
- }
-
- function negate($bool = false) {
- $this->negate = $bool;
- }
-
- function be($first, $second, $message = '%s') {
- return $this->runtime->assert(new EqualExpectation($first), $second, $message);
- }
-
- function be_equal($first, $second, $message = '%s') {
- return $this->be($first, $second, $message);
- }
-
- function be_empty($subject, $message = '%s') {
- $dumper = new SimpleDumper();
-
- return $this->be_true(empty($subject) == true, "[{$dumper->describeValue($subject)}] should be empty");
- }
-
- function be_true($result, $message = '%s') {
- return $this->runtime->assert(new TrueExpectation(), $result, $message);
- }
-
- function be_false($result, $message = '%s') {
- return $this->runtime->assert(new FalseExpectation(), $result, $message);
- }
-
- function be_null($value, $message = '%s') {
- $dumper = new SimpleDumper();
- $message = sprintf($message, '[' . $dumper->describeValue($value) . '] should be null');
- return $this->runtime->assert(new TrueExpectation(), ! isset($value), $message);
- }
-
- function be_a($object, $type, $message = '%s') {
- if (strtolower($type) == 'object')
- $type = 'stdClass';
- return $this->runtime->assert(new IsAExpectation($type),$object, $message);
- }
-
- function be_an($object, $type, $message = '%s') {
- return $this->be_a($object, $type, $message);
- }
-
- function be_within_margin($first, $second, $margin, $message = '%s') {
- return $this->runtime->assert(
- new WithinMarginExpectation($first, $margin),
- $second,
- $message);
- }
-
- function be_outside_margin($first, $second, $margin, $message = '%s') {
- return $this->runtime->assert(
- new assertOutsideMargin($first, $margin),
- $second,
- $message);
- }
-
- function be_identical($first, $second, $message = '%s') {
- return $this->runtime->assert(
- new IdenticalExpectation($first),
- $second,
- $message);
- }
-
- function be_reference_of(&$first, &$second, $message = '%s') {
- $dumper = new SimpleDumper();
- $message = sprintf(
- $message,
- '[' . $dumper->describeValue($first) .
- '] and [' . $dumper->describeValue($second) .
- '] should reference the same object');
- return $this->runtime->assert(new TrueExpectation(), SimpleTestCompatibility::isReference($first, $second), $message);
- }
-
- function be_clone_of(&$first, &$second, $message = '%s') {
- $dumper = new SimpleDumper();
- $message = sprintf(
- $message,
- '[' . $dumper->describeValue($first) .
- '] and [' . $dumper->describeValue($second) .
- '] should not be the same object');
- $identical = new IdenticalExpectation($first);
- return $this->runtime->assert(new TrueExpectation(),
- $identical->test($second) && ! SimpleTestCompatibility::isReference($first, $second),
- $message);
- }
-
- function be_copy_of(&$first, &$second, $message = '%s') {
- $dumper = new SimpleDumper();
- $message = sprintf(
- $message,
- "[" . $dumper->describeValue($first) .
- "] and [" . $dumper->describeValue($second) .
- "] should not be the same object");
- return $this->runtime->assert(new FaseExpectation(),
- SimpleTestCompatibility::isReference($first, $second),
- $message);
- }
-
- function contain($subject, $target, $message = '%s') {
- $dumper = new SimpleDumper();
- $message = "[ {$dumper->describeValue($subject)}] should contain [{$dumper->describeValue($target)}]";
-
- if (is_array($subject) && is_array($target)) {
- return $this->be_true(array_intersect($target, $subject) == $target, $message);
- } elseif (is_array($subject)) {
- return $this->be_true(in_array($target, $subject), $message);
- } elseif (is_string($subject)) {
- return $this->be_true(strpos($target, $subject) !== false, $message);
- }
- }
-
- function have($target, $count, $key, $messages = '%s') {
- $dumper = new SimpleDumper();
- $subject = null;
-
- if (is_array($target) && isset($target[$key]))
- $subject = $target[$key];
- elseif (is_object($target) && isset($target->$key))
- $subject = $target->$key;
-
- $result = count($subject);
- $messages = "Expecting count for [$key] should be [$count], got [$result]";
-
- return $this->be($result, $count, $messages);
- }
-
- function match($subject, $pattern, $message = '%s') {
- $regex = "/^[\/{#](.*)[\/}#][imsxeADSUXJu]*/sm";
-
- if (preg_match($regex, $subject)) {
- list($subject, $pattern) = array($pattern, $subject);
- }
-
- return $this->runtime->assert(
- new PatternExpectation($pattern),
- $subject,
- $message);
- }
-
- function expect_error($message = '%s') {
- $context = &SimpleTest::getContext();
- $queue = &$context->get('SimpleErrorQueue');
- $queue->expectError($this->runtime->_coerceExpectation($this->negate), $message);
- }
-
- function expect_exception($message = '%s') {
- $context = &SimpleTest::getContext();
- $queue = &$context->get('SimpleExceptionTrap');
- // :HACK: Directly substituting in seems to cause a segfault with
- // Zend Optimizer on some systems
- $line = $this->runtime->getAssertionLine();
- $queue->expectException($this->negate, $message . $line);
- }
- }
-
-
- ?>