diff --git a/README.md b/README.md index 88c3b7b9..8fc63ef8 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ class AttributeTest extends TestCase // or you can create your assertion by chaining $this->assert($result, exactly_equals, 123); - // assertThat for convenience - assertThat($answer, is_an_associative_array); + // you may prefer assert_that + assert_that($answer, is_an_associative_array); // while generally not recommended, you can use code blocks (notice $self instead of $this) $this->assert('`$self->calc->add(3, 5)` equals 8'); diff --git a/concise b/concise new file mode 100755 index 00000000..9b9e4e88 --- /dev/null +++ b/concise @@ -0,0 +1,143 @@ +#!/usr/bin/env php +width = exec('tput cols'); + } + + public function write($buffer) + { + if(substr($buffer, 0, 7) !== 'PHPUnit') { + return parent::write($buffer); + } + } + + public function endTest(PHPUnit_Framework_Test $test, $time) + { + if ($test instanceof PHPUnit_Framework_TestCase) { + $this->numAssertions += $test->getNumAssertions(); + } + else if ($test instanceof PHPUnit_Extensions_PhptTestCase) { + $this->numAssertions++; + } + + ++$this->numTestsRun; + $this->update(); + } + + protected function printHeader() + { + echo "\n"; + } + + protected function printFooter(PHPUnit_Framework_TestResult $result) + { + if (count($result) === 0) { + $message = 'No tests executed!'; + echo "\033[2A\033[0;30m\033[42m{$message}\033[0m"; + } + else if ($result->wasSuccessful() && + $result->allHarmless() && + $result->allCompletelyImplemented() && + $result->noneSkipped()) { + $message = 'OK'; + echo "\033[2A\033[0;30m\033[42m{$message}\033[0m"; + } + else if ((!$result->allCompletelyImplemented() || + !$result->allHarmless() || + !$result->noneSkipped()) && + $result->wasSuccessful()) { + $message = 'OK, but incomplete, skipped, or risky tests!'; + echo "\033[2A\033[0;30m\033[42m{$message}\033[0m"; + } + + parent::printHeader(); + } + + protected function repeat($string, $times) + { + if($times < 0) { + return ''; + } + return str_repeat($string, $times); + } + + protected function update() + { + if($this->numTestsRun > 1) { + echo "\033[2A"; + } + + $assertionString = $this->numAssertions . ' assertion' . ($this->numAssertions == 1 ? '' : 's'); + echo $assertionString . $this->repeat(' ', $this->width - (2 * $this->numTestsWidth) - 11 - strlen($assertionString)); + $done = $this->numTestsRun / $this->numTests; + printf(' %' . $this->numTestsWidth . 'd / %' . $this->numTestsWidth . "d (%3s%%)\n", + $this->numTestsRun, $this->numTests, floor($done * 100)); + + $failures = 0; + if($this->numTestsFailed) { + $failures = ceil($this->width * $this->numTestsFailed / $this->numTests); + } + $successes = floor($this->width * $done) - $failures; + echo "\033[42m" . $this->repeat(' ', $successes); + echo "\033[41m" . $this->repeat(' ', $failures); + echo "\033[0m" . $this->repeat('_', $this->width - $successes - $failures) . "\n"; + } + + protected function printDefect(PHPUnit_Framework_TestFailure $defect, $count) + { + $this->printDefectHeader($defect, $count); + $this->printDefectTrace($defect); + } + + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + ++$this->numTestsFailed; + } + + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + ++$this->numTestsFailed; + } + + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } + + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + } +} + +class Concise_TestRunner extends PHPUnit_TextUI_TestRunner +{ +} + +class Concise_Command extends PHPUnit_TextUI_Command +{ + protected function createRunner() + { + $runner = new Concise_TestRunner($this->arguments['loader']); + $runner->setPrinter(new Concise_ResultPrinter()); + return $runner; + } +} + +$command = new Concise_Command(); +$command->run($_SERVER['argv'], true); diff --git a/src/Concise/Assertion.php b/src/Concise/Assertion.php index 7e6de9ab..481a4a4c 100644 --- a/src/Concise/Assertion.php +++ b/src/Concise/Assertion.php @@ -120,11 +120,11 @@ protected function executeAssertion() $args = $this->checkDataTypes($args); } - $answer = $this->getMatcher()->match($result['syntax'], $args); + $answer = $this->getMatcher()->match($this->originalSyntax, $args); if(true === $answer || null === $answer) { return; } - $message = $this->getMatcher()->renderFailureMessage($result['syntax'], $result['arguments']); + $message = $this->getMatcher()->renderFailureMessage($result['syntax'], $args); throw new \PHPUnit_Framework_AssertionFailedError($message); } diff --git a/src/Concise/Matcher/AbstractMatcher.php b/src/Concise/Matcher/AbstractMatcher.php index 3cd12fd6..6053e8f4 100644 --- a/src/Concise/Matcher/AbstractMatcher.php +++ b/src/Concise/Matcher/AbstractMatcher.php @@ -27,9 +27,4 @@ public function renderFailureMessage($syntax, array $data = array()) $renderer = new SyntaxRenderer(); return $renderer->render($syntax, $data); } - - protected function getComparer() - { - return new Comparer(); - } } diff --git a/src/Concise/Matcher/Between.php b/src/Concise/Matcher/Between.php new file mode 100644 index 00000000..8f4be12c --- /dev/null +++ b/src/Concise/Matcher/Between.php @@ -0,0 +1,21 @@ + self::DESCRIPTION, + '?:number between ?:number and ?:number' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return $data[0] >= $data[1] && $data[0] <= $data[2]; + } +} diff --git a/src/Concise/Matcher/DoesNotMatchRegularExpression.php b/src/Concise/Matcher/DoesNotMatchRegularExpression.php index 38676a09..a09b6e68 100644 --- a/src/Concise/Matcher/DoesNotMatchRegularExpression.php +++ b/src/Concise/Matcher/DoesNotMatchRegularExpression.php @@ -2,8 +2,6 @@ namespace Concise\Matcher; -use \Concise\Services\ToStringConverter; - class DoesNotMatchRegularExpression extends MatchesRegularExpression { const DESCRIPTION = 'Assert a string does not match a regular expression.'; @@ -11,15 +9,15 @@ class DoesNotMatchRegularExpression extends MatchesRegularExpression public function supportedSyntaxes() { return array( - '? does not match regular expression ?:regex' => self::DESCRIPTION, - '? doesnt match regular expression ?:regex' => self::DESCRIPTION, - '? does not match regex ?:regex' => self::DESCRIPTION, - '? doesnt match regex ?:regex' => self::DESCRIPTION, + '?:string does not match regular expression ?:regex' => self::DESCRIPTION, + '?:string doesnt match regular expression ?:regex' => self::DESCRIPTION, + '?:string does not match regex ?:regex' => self::DESCRIPTION, + '?:string doesnt match regex ?:regex' => self::DESCRIPTION, ); } public function match($syntax, array $data = array()) { - return !parent::match('? matches regular expression ?:regex', $data); + return !parent::match(null, $data); } } diff --git a/src/Concise/Matcher/Equals.php b/src/Concise/Matcher/Equals.php index f2af61bc..5522cd2b 100644 --- a/src/Concise/Matcher/Equals.php +++ b/src/Concise/Matcher/Equals.php @@ -18,6 +18,6 @@ public function supportedSyntaxes() public function match($syntax, array $data = array()) { - return $this->getComparer()->compare($data[0], $data[1]); + return $data[0] == $data[1]; } } diff --git a/src/Concise/Matcher/HasItem.php b/src/Concise/Matcher/HasItem.php new file mode 100644 index 00000000..674c07f2 --- /dev/null +++ b/src/Concise/Matcher/HasItem.php @@ -0,0 +1,31 @@ + self::DESCRIPTION, + '?:array has item ?:array' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + if($syntax === self::SPLIT_SYNTAX) { + return $this->match(null, array($data[0], array($data[1] => $data[2]))); + } + foreach($data[0] as $key => $value) { + if(array($key => $value) == $data[1]) { + return true; + } + } + return false; + } +} diff --git a/src/Concise/Matcher/HasItems.php b/src/Concise/Matcher/HasItems.php new file mode 100644 index 00000000..f6b1c7e7 --- /dev/null +++ b/src/Concise/Matcher/HasItems.php @@ -0,0 +1,28 @@ + self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + if(count($data[1]) === 0) { + return true; + } + foreach($data[1] as $key => $value) { + if(!parent::match($data[0], array($data[0], array($key => $value)))) { + return false; + } + } + return true; + } +} diff --git a/src/Concise/Matcher/HasValues.php b/src/Concise/Matcher/HasValues.php new file mode 100644 index 00000000..23898e4e --- /dev/null +++ b/src/Concise/Matcher/HasValues.php @@ -0,0 +1,26 @@ + self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + $keys = array_values($data[0]); + foreach($data[1] as $key) { + if(!in_array($key, $keys)) { + return false; + } + } + return true; + } +} diff --git a/src/Concise/Matcher/IsAnEmptyArray.php b/src/Concise/Matcher/IsAnEmptyArray.php new file mode 100644 index 00000000..5ef31b8d --- /dev/null +++ b/src/Concise/Matcher/IsAnEmptyArray.php @@ -0,0 +1,21 @@ + self::DESCRIPTION, + '?:array is an empty array' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return count($data[0]) === 0; + } +} diff --git a/src/Concise/Matcher/IsBlank.php b/src/Concise/Matcher/IsBlank.php new file mode 100644 index 00000000..6eb4a425 --- /dev/null +++ b/src/Concise/Matcher/IsBlank.php @@ -0,0 +1,18 @@ + 'Assert a string is zero length.', + ); + } + + public function match($syntax, array $data = array()) + { + return $data[0] === ''; + } +} diff --git a/src/Concise/Matcher/IsFalse.php b/src/Concise/Matcher/IsFalse.php index db0d2bf7..1871dcf9 100644 --- a/src/Concise/Matcher/IsFalse.php +++ b/src/Concise/Matcher/IsFalse.php @@ -13,6 +13,6 @@ public function supportedSyntaxes() public function match($syntax, array $data = array()) { - return $this->getComparer()->compare($data[0], false); + return $data[0] === false; } } diff --git a/src/Concise/Matcher/IsGreaterThan.php b/src/Concise/Matcher/IsGreaterThan.php new file mode 100644 index 00000000..2146a880 --- /dev/null +++ b/src/Concise/Matcher/IsGreaterThan.php @@ -0,0 +1,22 @@ + self::DESCRIPTION, + '?:number greater than ?:number' => self::DESCRIPTION, + '?:number gt ?:number' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return $data[0] > $data[1]; + } +} diff --git a/src/Concise/Matcher/IsGreaterThanEqual.php b/src/Concise/Matcher/IsGreaterThanEqual.php new file mode 100644 index 00000000..124ca686 --- /dev/null +++ b/src/Concise/Matcher/IsGreaterThanEqual.php @@ -0,0 +1,22 @@ + self::DESCRIPTION, + '?:number greater than or equal ?:number' => self::DESCRIPTION, + '?:number gte ?:number' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return $data[0] >= $data[1]; + } +} diff --git a/src/Concise/Matcher/IsLessThan.php b/src/Concise/Matcher/IsLessThan.php new file mode 100644 index 00000000..ea29fcb0 --- /dev/null +++ b/src/Concise/Matcher/IsLessThan.php @@ -0,0 +1,22 @@ + self::DESCRIPTION, + '?:number less than ?:number' => self::DESCRIPTION, + '?:number lt ?:number' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return $data[0] < $data[1]; + } +} diff --git a/src/Concise/Matcher/IsLessThanEqual.php b/src/Concise/Matcher/IsLessThanEqual.php new file mode 100644 index 00000000..b49d0b7c --- /dev/null +++ b/src/Concise/Matcher/IsLessThanEqual.php @@ -0,0 +1,22 @@ + self::DESCRIPTION, + '?:number less than or equal ?:number' => self::DESCRIPTION, + '?:number lte ?:number' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return $data[0] <= $data[1]; + } +} diff --git a/src/Concise/Matcher/IsNotAnEmptyArray.php b/src/Concise/Matcher/IsNotAnEmptyArray.php new file mode 100644 index 00000000..9b267118 --- /dev/null +++ b/src/Concise/Matcher/IsNotAnEmptyArray.php @@ -0,0 +1,21 @@ + self::DESCRIPTION, + '?:array is not an empty array' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return !parent::match(null, $data); + } +} diff --git a/src/Concise/Matcher/IsNotBlank.php b/src/Concise/Matcher/IsNotBlank.php new file mode 100644 index 00000000..b01ae79a --- /dev/null +++ b/src/Concise/Matcher/IsNotBlank.php @@ -0,0 +1,18 @@ + 'Assert a string has at least one character.', + ); + } + + public function match($syntax, array $data = array()) + { + return !parent::match(null, $data); + } +} diff --git a/src/Concise/Matcher/IsNotInstanceOf.php b/src/Concise/Matcher/IsNotInstanceOf.php new file mode 100644 index 00000000..8f3cec67 --- /dev/null +++ b/src/Concise/Matcher/IsNotInstanceOf.php @@ -0,0 +1,22 @@ + self::DESCRIPTION, + '?:object is not instance of ?:class' => self::DESCRIPTION, + '?:object not instance of ?:class' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return !parent::match(null, $data); + } +} diff --git a/src/Concise/Matcher/IsNotUnique.php b/src/Concise/Matcher/IsNotUnique.php new file mode 100644 index 00000000..d08975b0 --- /dev/null +++ b/src/Concise/Matcher/IsNotUnique.php @@ -0,0 +1,18 @@ + 'Assert that an array only has at least one element that is repeated.', + ); + } + + public function match($syntax, array $data = array()) + { + return !parent::match(null, $data); + } +} diff --git a/src/Concise/Matcher/IsTrue.php b/src/Concise/Matcher/IsTrue.php index 9c45db8d..fcce6afd 100644 --- a/src/Concise/Matcher/IsTrue.php +++ b/src/Concise/Matcher/IsTrue.php @@ -13,6 +13,6 @@ public function supportedSyntaxes() public function match($syntax, array $data = array()) { - return $this->getComparer()->compare($data[0], true); + return $data[0] === true; } } diff --git a/src/Concise/Matcher/IsUnique.php b/src/Concise/Matcher/IsUnique.php new file mode 100644 index 00000000..6c61f076 --- /dev/null +++ b/src/Concise/Matcher/IsUnique.php @@ -0,0 +1,18 @@ + 'Assert that an array only contains unique values.', + ); + } + + public function match($syntax, array $data = array()) + { + return count($data[0]) === count(array_unique($data[0])); + } +} diff --git a/src/Concise/Matcher/MatchesRegularExpression.php b/src/Concise/Matcher/MatchesRegularExpression.php index 37d73bb5..b5731aaa 100644 --- a/src/Concise/Matcher/MatchesRegularExpression.php +++ b/src/Concise/Matcher/MatchesRegularExpression.php @@ -2,23 +2,20 @@ namespace Concise\Matcher; -use \Concise\Services\ToStringConverter; - class MatchesRegularExpression extends AbstractMatcher { + const DESCRIPTION = 'Assert a string matches a regular expression'; + public function supportedSyntaxes() { return array( - '? matches regular expression ?:regex' => 'Assert a string matches a regular expression', - '? matches regex ?:regex' => 'Assert a string matches a regular expression', + '?:string matches regular expression ?:regex' => self::DESCRIPTION, + '?:string matches regex ?:regex' => self::DESCRIPTION, ); } public function match($syntax, array $data = array()) { - $converter = new ToStringConverter(); - $subject = $converter->convertToString($data[0]); - $pattern = $converter->convertToString($data[1]); - return preg_match('/' . $pattern . '/', $subject) === 1; + return preg_match($data[1], $data[0]) === 1; } } diff --git a/src/Concise/Matcher/NotBetween.php b/src/Concise/Matcher/NotBetween.php new file mode 100644 index 00000000..f4d42ec4 --- /dev/null +++ b/src/Concise/Matcher/NotBetween.php @@ -0,0 +1,21 @@ + self::DESCRIPTION, + '?:number not between ?:number and ?:number' => self::DESCRIPTION, + ); + } + + public function match($syntax, array $data = array()) + { + return !parent::match(null, $data); + } +} diff --git a/src/Concise/Matcher/StringEndsWith.php b/src/Concise/Matcher/StringEndsWith.php index fa112dbb..8417c05c 100644 --- a/src/Concise/Matcher/StringEndsWith.php +++ b/src/Concise/Matcher/StringEndsWith.php @@ -2,23 +2,17 @@ namespace Concise\Matcher; -use \Concise\Services\ToStringConverter; - class StringEndsWith extends AbstractMatcher { public function supportedSyntaxes() { return array( - '? ends with ?' => 'Assert a string ends with another string.', + '?:string ends with ?:string' => 'Assert a string ends with another string.', ); } public function match($syntax, array $data = array()) { - $converter = new ToStringConverter(); - $haystack = $converter->convertToString($data[0]); - $needle = $converter->convertToString($data[1]); - - return ((substr($haystack, strlen($haystack) - strlen($needle)) === $needle)); + return ((substr($data[0], strlen($data[0]) - strlen($data[1])) === $data[1])); } } diff --git a/src/Concise/Matcher/StringStartsWith.php b/src/Concise/Matcher/StringStartsWith.php index 1b2a0cf9..1e674eaf 100644 --- a/src/Concise/Matcher/StringStartsWith.php +++ b/src/Concise/Matcher/StringStartsWith.php @@ -2,23 +2,17 @@ namespace Concise\Matcher; -use \Concise\Services\ToStringConverter; - class StringStartsWith extends AbstractMatcher { public function supportedSyntaxes() { return array( - '? starts with ?' => 'Assert a string starts (begins) with another string.', + '?:string starts with ?:string' => 'Assert a string starts (begins) with another string.', ); } public function match($syntax, array $data = array()) { - $converter = new ToStringConverter(); - $haystack = $converter->convertToString($data[0]); - $needle = $converter->convertToString($data[1]); - - return ((substr($haystack, 0, strlen($needle)) === $needle)); + return ((substr($data[0], 0, strlen($data[1])) === $data[1])); } } diff --git a/src/Concise/Mock/Action/AbstractAction.php b/src/Concise/Mock/Action/AbstractAction.php index c5e4bb51..93359c50 100644 --- a/src/Concise/Mock/Action/AbstractAction.php +++ b/src/Concise/Mock/Action/AbstractAction.php @@ -4,5 +4,5 @@ abstract class AbstractAction { - public abstract function getWillAction(\PHPUnit_Framework_TestCase $testCase); + public abstract function getActionCode(); } diff --git a/src/Concise/Mock/Action/ReturnValueAction.php b/src/Concise/Mock/Action/ReturnValueAction.php index 73595132..dbe8b697 100644 --- a/src/Concise/Mock/Action/ReturnValueAction.php +++ b/src/Concise/Mock/Action/ReturnValueAction.php @@ -11,9 +11,9 @@ public function __construct($value) $this->value = $value; } - public function getWillAction(\PHPUnit_Framework_TestCase $testCase) + public function getActionCode() { - return $testCase->returnValue($this->value); + return 'return ' . var_export($this->value, true) . ';'; } public function getValue() diff --git a/src/Concise/Mock/Action/ThrowAction.php b/src/Concise/Mock/Action/ThrowAction.php index 0c4409c0..0b9499a2 100644 --- a/src/Concise/Mock/Action/ThrowAction.php +++ b/src/Concise/Mock/Action/ThrowAction.php @@ -4,15 +4,18 @@ class ThrowAction extends AbstractAction { + public static $cache = array(); + protected $exception; public function __construct($exception) { - $this->exception = $exception; + $this->cacheId = md5(rand()); + self::$cache[$this->cacheId] = $exception; } - public function getWillAction(\PHPUnit_Framework_TestCase $testCase) + public function getActionCode() { - return $testCase->throwException($this->exception); + return 'throw \Concise\Mock\Action\ThrowAction::$cache["' . $this->cacheId . '"];'; } } diff --git a/src/Concise/Mock/ClassCompiler.php b/src/Concise/Mock/ClassCompiler.php new file mode 100644 index 00000000..d65b7cfc --- /dev/null +++ b/src/Concise/Mock/ClassCompiler.php @@ -0,0 +1,88 @@ +className = ltrim($className, '\\'); + $this->mockUnique = '_' . substr(md5(rand()), 24); + $this->niceMock = $niceMock; + $this->constructorArgs = $constructorArgs; + } + + protected function getNamespaceName() + { + $parts = explode('\\', $this->className); + array_pop($parts); + return implode('\\', $parts); + } + + protected function getClassName() + { + $parts = explode('\\', $this->className); + return $parts[count($parts) - 1]; + } + + public function generateCode() + { + $refClass = new \ReflectionClass($this->className); + $prototypeBuilder = new PrototypeBuilder(); + $prototypeBuilder->hideAbstract = true; + + $code = ''; + if($this->getNamespaceName()) { + $code = "namespace " . $this->getNamespaceName() . "; "; + } + + $methods = array(); + if(!$this->niceMock) { + foreach($refClass->getMethods() as $method) { + $methods[$method->getName()] = $prototypeBuilder->getPrototype($method) . ' { throw new \\Exception("' . + $method->getName() . '() does not have an associated action - consider a niceMock()?"); }'; + } + } + + foreach($this->rules as $method => $rule) { + $action = $rule['action']; + $realMethod = new \ReflectionMethod($this->className, $method); + $methods[$method] = $prototypeBuilder->getPrototype($realMethod) . " { if(!array_key_exists('$method', \$this->_methodCalls)) { \$this->_methodCalls['$method'] = array(); } \$this->_methodCalls['$method'][] = func_get_args(); " . $action->getActionCode() . ' }'; + } + + $methods['getCallsForMethod'] = 'public function getCallsForMethod($method) { return array_key_exists($method, $this->_methodCalls) ? $this->_methodCalls[$method] : array(); }'; + + unset($methods['__construct']); + + return $code . "class {$this->getMockName()} extends \\{$this->className} { public \$_methodCalls = array(); " . implode(" ", $methods) . "}"; + } + + protected function getMockName() + { + return $this->getClassName() . $this->mockUnique; + } + + public function newInstance() + { + $reflect = eval($this->generateCode() . " return new \\ReflectionClass('{$this->getNamespaceName()}\\{$this->getMockName()}');"); + return $reflect->newInstanceArgs($this->constructorArgs); + } + + public function setRules(array $rules) + { + $this->rules = $rules; + } +} diff --git a/src/Concise/Mock/MockBuilder.php b/src/Concise/Mock/MockBuilder.php index 2987b02c..3de3969c 100644 --- a/src/Concise/Mock/MockBuilder.php +++ b/src/Concise/Mock/MockBuilder.php @@ -17,7 +17,9 @@ class MockBuilder protected $currentRule; - public function __construct(\PHPUnit_Framework_TestCase $testCase, $className, $niceMock) + protected $constructorArgs; + + public function __construct(\PHPUnit_Framework_TestCase $testCase, $className, $niceMock, array $constructorArgs = array()) { $this->testCase = $testCase; if(!class_exists($className)) { @@ -25,6 +27,7 @@ public function __construct(\PHPUnit_Framework_TestCase $testCase, $className, $ } $this->className = $className; $this->niceMock = $niceMock; + $this->constructorArgs = $constructorArgs; } protected function addRule($method, Action\AbstractAction $action, $times = -1) @@ -32,9 +35,10 @@ protected function addRule($method, Action\AbstractAction $action, $times = -1) $this->currentRule = $method; $this->mockedMethods[] = $method; $this->rules[$method] = array( - 'action' => $action, - 'times' => $times, - 'with' => null, + 'action' => $action, + 'times' => $times, + 'with' => null, + 'calledTimes' => 0, ); } @@ -54,63 +58,13 @@ public function stub($arg) return $this; } - protected function getAllMethodNamesForClass() - { - $class = new \ReflectionClass($this->className); - $methodNames = array(); - foreach($class->getMethods() as $method) { - $methodNames[] = $method->getName(); - } - return $methodNames; - } - - protected function stubMethod($mock, $method, $will, $times = -1, $with = null) - { - $expect = $this->testCase->any(); - if($times >= 0) { - $expect = $this->testCase->exactly($times); - } - $m = $mock->expects($expect) - ->method($method); - if(null !== $with) { - $m = call_user_func_array(array($m, 'with'), $with); - } - $m->will($will); - } - public function done() { - $class = $this->className; - $originalObject = new $class(); - - $allMethods = array_unique($this->getAllMethodNamesForClass() + array_keys($this->rules)); - $mock = $this->testCase->getMock($this->className, $allMethods); - foreach($this->rules as $method => $rule) { - $action = $rule['action']; - $this->stubMethod($mock, $method, $action->getWillAction($this->testCase), $rule['times'], $rule['with']); - } - - // throw exception for remaining methods - if($this->niceMock) { - foreach($allMethods as $method) { - if(in_array($method, $this->mockedMethods)) { - continue; - } - $will = $this->testCase->returnCallback(array($originalObject, $method)); - $this->stubMethod($mock, $method, $will); - } - } - else { - foreach($allMethods as $method) { - if(in_array($method, $this->mockedMethods)) { - continue; - } - $will = $this->testCase->throwException(new \Exception("$method() does not have an associated action - consider a niceMock()?")); - $this->stubMethod($mock, $method, $will); - } - } - - return $mock; + $compiler = new ClassCompiler($this->className, $this->niceMock, $this->constructorArgs); + $compiler->setRules($this->rules); + $mockInstance = $compiler->newInstance(); + $this->testCase->addMockInstance($this, $mockInstance); + return $mockInstance; } protected function hasAction() @@ -185,4 +139,9 @@ public function with() $this->rules[$this->currentRule]['with'] = func_get_args(); return $this; } + + public function getRules() + { + return $this->rules; + } } diff --git a/src/Concise/Mock/PrototypeBuilder.php b/src/Concise/Mock/PrototypeBuilder.php new file mode 100644 index 00000000..6c3fbb8b --- /dev/null +++ b/src/Concise/Mock/PrototypeBuilder.php @@ -0,0 +1,42 @@ +getModifiers())); + if($this->hideAbstract) { + $modifiers = str_replace('abstract ', '', $modifiers); + } + $parameters = array(); + foreach($method->getParameters() as $p) { + $param = '$' . $p->getName(); + if($p->isPassedbyReference()) { + $param = '&' . $param; + } + if($p->getClass()) { + $param = '\\' . $p->getClass()->name . ' ' . $param; + } + else if($p->isArray()) { + $param = 'array ' . $param; + } + else if(method_exists($p, 'isCallable') && $p->isCallable()) { + $param = 'callable ' . $param; + } + if($p->isOptional()) { + try { + $param .= ' = ' . var_export($p->getDefaultValue(), true); + } + catch(\ReflectionException $e) { + $param .= ' = NULL'; + } + } + $parameters[] = $param; + } + return $modifiers . ' function ' . $method->getName() . "(" . implode(', ', $parameters) . ")"; + } +} diff --git a/src/Concise/Services/AssertionBuilder.php b/src/Concise/Services/AssertionBuilder.php index d1cede56..5fe8ea14 100644 --- a/src/Concise/Services/AssertionBuilder.php +++ b/src/Concise/Services/AssertionBuilder.php @@ -4,6 +4,7 @@ use \Concise\Syntax\MatcherParser; use \Concise\Assertion; +use \Concise\Matcher\IsTrue; class AssertionBuilder { @@ -16,6 +17,11 @@ public function __construct(array $args) public function getAssertion() { + $matcherParser = MatcherParser::getInstance(); + if(count($this->args) === 1 && is_bool($this->args[0])) { + return $matcherParser->compile($this->args[0] ? 'true' : 'false'); + } + $syntax = array(); $data = array(); $argc = count($this->args); @@ -30,7 +36,6 @@ public function getAssertion() } } - $matcherParser = MatcherParser::getInstance(); $syntaxString = implode(' ', $syntax); return $matcherParser->compile($syntaxString, $data); } diff --git a/src/Concise/Services/Comparer.php b/src/Concise/Services/Comparer.php deleted file mode 100644 index 1f0b39ee..00000000 --- a/src/Concise/Services/Comparer.php +++ /dev/null @@ -1,35 +0,0 @@ -convertToString = new ToStringConverter; - } - - public function setConvertToString(ToStringConverter $convertToString) - { - $this->convertToString = $convertToString; - } - - protected function normalize($value) - { - if(!is_resource($value) && !is_bool($value) && !is_null($value)) { - $value = $this->convertToString->convertToString($value); - } - return $value; - } - - public function compare($a, $b) - { - $a = $this->normalize($a); - $b = $this->normalize($b); - return $a === $b; - } -} diff --git a/src/Concise/Services/DataTypeChecker.php b/src/Concise/Services/DataTypeChecker.php index e168e651..55dd5e62 100644 --- a/src/Concise/Services/DataTypeChecker.php +++ b/src/Concise/Services/DataTypeChecker.php @@ -49,6 +49,9 @@ protected function throwInvalidArgumentException(array $acceptedTypes, $value, $ if(in_array('class', $acceptedTypes) && is_string($value) && substr($value, 0, 1) === '\\') { return substr($value, 1); } + if(in_array('regex', $acceptedTypes)) { + return $value; + } return $value; } $accepts = implode(' or ', $acceptedTypes); @@ -82,21 +85,30 @@ protected function getType($value) return gettype($value); } + protected function singleMatch($type, $value) + { + return $type === $this->simpleType($this->getType($value)); + } + protected function matches($type, $value) { - return $this->simpleType($type) === $this->simpleType($this->getType($value)); + if($type === 'number') { + return $this->singleMatch('int', $value) || $this->singleMatch('float', $value) || is_numeric($value); + } + return $this->singleMatch($this->simpleType($type), $value); } protected function simpleType($type) { - if($type === 'integer') { - $type = 'int'; - } - else if($type === 'double') { - $type = 'float'; - } - else if($type === 'class') { - $type = 'string'; + $aliases = array( + 'integer' => 'int', + 'double' => 'float', + 'class' => 'string', + 'bool' => 'boolean', + 'regex' => 'string', + ); + if(array_key_exists($type, $aliases)) { + return $aliases[$type]; } return $type; } diff --git a/src/Concise/Services/ToStringConverter.php b/src/Concise/Services/ToStringConverter.php deleted file mode 100644 index d0dbff19..00000000 --- a/src/Concise/Services/ToStringConverter.php +++ /dev/null @@ -1,28 +0,0 @@ -convertToString($value()); - } - catch(\Exception $e) { - return $e->getMessage(); - } - } - if(is_array($value) || (is_object($value) && !method_exists($value, '__toString'))) { - return json_encode($value); - } - return (string) $value; - } -} diff --git a/src/Concise/Syntax/Lexer.php b/src/Concise/Syntax/Lexer.php index 02477e93..d8e3ab2b 100644 --- a/src/Concise/Syntax/Lexer.php +++ b/src/Concise/Syntax/Lexer.php @@ -68,7 +68,7 @@ protected function consumeCode($string, &$startIndex) protected function consumeRegexp($string, &$startIndex) { - return $this->consumeUntilToken($string, '/', $startIndex); + return '/' . $this->consumeUntilToken($string, '/', $startIndex) . '/'; } /** diff --git a/src/Concise/Syntax/MatcherParser.php b/src/Concise/Syntax/MatcherParser.php index 534be5ec..a41b7c2d 100644 --- a/src/Concise/Syntax/MatcherParser.php +++ b/src/Concise/Syntax/MatcherParser.php @@ -25,16 +25,7 @@ public function __construct() protected function getRawSyntax($syntax) { - if(!array_key_exists($syntax, $this->syntaxCache)) { - if(strpos($syntax, ':') === false) { - $this->syntaxCache[$syntax] = $syntax; - } - else { - $parse = $this->lexer->parse($syntax); - $this->syntaxCache[$syntax] = $parse['syntax']; - } - } - return $this->syntaxCache[$syntax]; + return preg_replace('/\\?:[^\s$]+/i', '?', $syntax); } /** @@ -43,26 +34,11 @@ protected function getRawSyntax($syntax) */ public function getMatcherForSyntax($syntax) { - $found = array(); - foreach($this->matchers as $matcher) { - $service = new MatcherSyntaxAndDescription(); - $syntaxes = array_keys($service->process($matcher->supportedSyntaxes())); - foreach($syntaxes as $s) { - if($this->getRawSyntax($syntax) === $this->getRawSyntax($s)) { - $found[] = array( - 'matcher' => $matcher, - 'originalSyntax' => $s, - ); - } - } - } - if(count($found) === 0) { - throw new \Exception("No such matcher for syntax '$syntax'."); - } - if(count($found) > 1) { - throw new \Exception("Ambiguous syntax for '$syntax'."); + $rawSyntax = $this->getRawSyntax($syntax); + if(array_key_exists($rawSyntax, $this->syntaxCache)) { + return $this->syntaxCache[$rawSyntax]; } - return $found[0]; + throw new \Exception("No such matcher for syntax '$syntax'."); } /** @@ -79,19 +55,6 @@ public function compile($string, array $data = array()) return $assertion; } - /** - * @param string $matcherClass - */ - public function matcherIsRegistered($matcherClass) - { - foreach($this->matchers as $matcher) { - if(get_class($matcher) === $matcherClass) { - return true; - } - } - return false; - } - protected function clearKeywordCache() { $this->keywords = array(); @@ -99,6 +62,19 @@ protected function clearKeywordCache() public function registerMatcher(\Concise\Matcher\AbstractMatcher $matcher) { + $service = new MatcherSyntaxAndDescription(); + $allSyntaxes = array_keys($service->process($matcher->supportedSyntaxes())); + foreach($allSyntaxes as $syntax) { + $rawSyntax = $this->getRawSyntax($syntax); + if(array_key_exists($rawSyntax, $this->syntaxCache)) { + throw new \Exception("Syntax '$syntax' is already declared."); + } + $this->syntaxCache[$rawSyntax] = array( + 'matcher' => $matcher, + 'originalSyntax' => $syntax, + ); + } + $this->matchers[] = $matcher; $this->clearKeywordCache(); return true; diff --git a/src/Concise/TestCase.php b/src/Concise/TestCase.php index 8980cc0d..dbd31609 100644 --- a/src/Concise/TestCase.php +++ b/src/Concise/TestCase.php @@ -9,6 +9,8 @@ class TestCase extends \PHPUnit_Framework_TestCase { + protected $_mocks = array(); + protected function getMatcherParserInstance() { return MatcherParser::getInstance(); @@ -36,22 +38,6 @@ public function getData() return get_object_vars($this); } - /** - * @param string $class - */ - protected function getStub($class, array $methods, array $constructorArgs = array()) - { - // @test force class to exist - // @test force class to be fully qualified - $stub = $this->getMock($class, array_keys($methods), $constructorArgs); - foreach($methods as $method => $returnValue) { - $stub->expects($this->any()) - ->method($method) - ->will($this->returnValue($returnValue)); - } - return $stub; - } - protected function getRealTestName() { $name = substr($this->getName(), 20); @@ -77,7 +63,7 @@ public static function getPHPUnitProperties() public function assert($assertionString) { - if(count(func_get_args()) > 1) { + if(count(func_get_args()) > 1 || is_bool($assertionString)) { $builder = new AssertionBuilder(func_get_args()); $assertion = $builder->getAssertion(); } @@ -94,17 +80,46 @@ public function tearDown() $assertion = str_replace("_", " ", substr($this->getName(), 5)); $this->assert($assertion); } + foreach($this->_mocks as $mock) { + foreach($mock['mockBuilder']->getRules() as $method => $rule) { + // Negative times means it is a stub. + if($rule['times'] < 0) { + continue; + } + + // @todo This if statement is only required while we make the transition to the new + // ClassBuilder, then it can be removed. + if(method_exists($mock['instance'], 'getCallsForMethod')) { + if(null === $rule['with']) { + $this->assert(count($mock['instance']->getCallsForMethod($method)), equals, $rule['times']); + } + else { + foreach($mock['instance']->getCallsForMethod($method) as $call) { + $this->assert($call, exactly_equals, $rule['with']); + } + } + } + } + } parent::tearDown(); } - protected function mock($className = '\StdClass') + protected function mock($className = '\stdClass', array $constructorArgs = array()) { - return new MockBuilder($this, $className, false); + return new MockBuilder($this, $className, false, $constructorArgs); } - protected function niceMock($className = '\StdClass') + protected function niceMock($className = '\stdClass', array $constructorArgs = array()) { - return new MockBuilder($this, $className, true); + return new MockBuilder($this, $className, true, $constructorArgs); + } + + public function addMockInstance(MockBuilder $mockBuilder, $mockInstance) + { + $this->_mocks[] = array( + 'mockBuilder' => $mockBuilder, + 'instance' => $mockInstance, + ); } public function setUp() @@ -141,7 +156,7 @@ public function setUp() namespace { - function assertThat() + function assert_that() { global $_currentTestCase; call_user_func_array(array($_currentTestCase, 'assert'), func_get_args()); diff --git a/tests/Concise/AssertionTest.php b/tests/Concise/AssertionTest.php index 4a26616a..51d01883 100644 --- a/tests/Concise/AssertionTest.php +++ b/tests/Concise/AssertionTest.php @@ -12,26 +12,26 @@ class AssertionTest extends TestCase public function testCreatingAssertionRequiresTheAssertionString() { $assertion = new Assertion('? equals ?', new Matcher\Equals()); - $this->assertEquals('? equals ?', $assertion->getAssertion()); + $this->assert($assertion->getAssertion(), equals, '? equals ?'); } public function testCreatingAssertionWithoutProvidingDataIsAnEmptyArray() { $assertion = new Assertion('? equals ?', new Matcher\Equals()); - $this->assertEquals(array(), $assertion->getData()); + $this->assert($assertion->getData(), is_an_empty_array); } public function testSettingDataWhenCreatingAssertion() { $assertion = new Assertion('? equals ?', new Matcher\Equals(), array('abc', 'def')); - $this->assertEquals(array('abc', 'def'), $assertion->getData()); + $this->assert($assertion->getData(), equals, array('abc', 'def')); } public function testCreatingAssertionRequiresTheMatcher() { $matcher = new Matcher\Equals(); $assertion = new Assertion('? equals ?', $matcher); - $this->assertSame($matcher, $assertion->getMatcher()); + $this->assert($matcher, is_the_same_as, $assertion->getMatcher()); } public function testToStringRenderedData() @@ -44,20 +44,20 @@ public function testToStringRenderedData() ); $assertion = new Assertion('a equals b', $matcher, $data); $expected = "\n a (integer) = 123\n b (string) = \"abc\"\n c (string) = \"xyz\"\n"; - $this->assertEquals($expected, (string) $assertion); + $this->assert((string) $assertion, equals, $expected); } public function testCanSetDescriptiveString() { $assertion = new Assertion('? equals ?', new Matcher\Equals()); $assertion->setDescription('my description'); - $this->assertEquals('my description (? equals ?)', $assertion->getDescription()); + $this->assert($assertion->getDescription(), equals, 'my description (? equals ?)'); } public function testDescriptionReturnsAssertionIfNotSet() { $assertion = new Assertion('? equals ?', new Matcher\Equals()); - $this->assertEquals('? equals ?', $assertion->getDescription()); + $this->assert($assertion->getDescription(), equals, '? equals ?'); } /** @@ -98,15 +98,15 @@ public function testAssertionCodeCanUseAttributes() protected function getStubForAssertionThatReturnsData(array $data) { - return $this->getStub('\Concise\Assertion', array( - 'getData' => $data - ), array('true', new True())); + return $this->niceMock('\Concise\Assertion', array('true', new True())) + ->stub(array('getData' => $data)) + ->done(); } public function testDoNotShowPHPUnitPropertiesOnError() { $assertion = $this->getStubForAssertionThatReturnsData(self::getPHPUnitProperties()); - $this->assertEquals("", (string) $assertion); + $this->assert((string) $assertion, is_blank); } public function testDoNotShowDataSetOnError() @@ -114,12 +114,12 @@ public function testDoNotShowDataSetOnError() $assertion = $this->getStubForAssertionThatReturnsData(array( '__dataSet' => array() )); - $this->assertEquals("", (string) $assertion); + $this->assert((string) $assertion, is_blank); } public function testNoAttributesRendersAsAnEmptyString() { $assertion = $this->getStubForAssertionThatReturnsData(array()); - $this->assertEquals("", (string) $assertion); + $this->assert((string) $assertion, is_blank); } } diff --git a/tests/Concise/Matcher/AbstractMatcherTest.php b/tests/Concise/Matcher/AbstractMatcherTest.php index 5dcc8928..8ec73a3c 100644 --- a/tests/Concise/Matcher/AbstractMatcherTest.php +++ b/tests/Concise/Matcher/AbstractMatcherTest.php @@ -16,11 +16,6 @@ public function supportedSyntaxes() { return array(); } - - public function getComparer() - { - return parent::getComparer(); - } } class AbstractMatcherTest extends TestCase @@ -33,11 +28,6 @@ public function setUp() public function testDefaultRendererWorks() { - $this->assertEquals('', $this->matcher->renderFailureMessage('')); - } - - public function testHasAccessToComparer() - { - $this->assert('`$self->matcher->getComparer()` is instance of \Concise\Services\Comparer'); + $this->assert($this->matcher->renderFailureMessage(''), is_blank); } } diff --git a/tests/Concise/Matcher/AbstractMatcherTestCase.php b/tests/Concise/Matcher/AbstractMatcherTestCase.php index 4fabd7c7..9444add9 100644 --- a/tests/Concise/Matcher/AbstractMatcherTestCase.php +++ b/tests/Concise/Matcher/AbstractMatcherTestCase.php @@ -10,33 +10,18 @@ class AbstractMatcherTestCase extends TestCase { public function testExtendsAbstractMatcher() { - $this->assert('`$self->matcher` is instance of \Concise\Matcher\AbstractMatcher'); + $this->assert($this->matcher, is_instance_of, '\Concise\Matcher\AbstractMatcher'); } public function testCanRegisterMatcher() { $parser = new MatcherParser(); - $this->assertTrue($parser->registerMatcher($this->matcher)); - } - - public function testParserKnowsAboutMatcher() - { - $parser = MatcherParser::getInstance(); - $this->assertTrue($parser->matcherIsRegistered(get_class($this->matcher))); - } - - public function testSupportedSyntaxesAreUnique() - { - $service = new MatcherSyntaxAndDescription(); - $syntaxes = array_keys($service->process($this->matcher->supportedSyntaxes())); - $this->assertEquals(count($syntaxes), count(array_unique($syntaxes))); + $this->assert($parser->registerMatcher($this->matcher), is_true); } protected function createStdClassThatCanBeCastToString($value) { - return $this->getStub('\stdClass', array( - '__toString' => $value - )); + return $this->mock()->stub(array('__toString' => $value))->done(); } /** @@ -59,11 +44,10 @@ protected function assertMatcherFailureMessage($syntax, array $args, $failureMes protected function assertMatcherFailure($syntax, array $args = array()) { try { - $result = $this->matcher->match($syntax, $args); - $this->assertFalse($result); + $this->assert($this->matcher->match($syntax, $args), is_false); } catch(DidNotMatchException $e) { - $this->assertTrue(true); + $this->assert(true); } } @@ -72,21 +56,18 @@ protected function assertMatcherFailure($syntax, array $args = array()) */ protected function assertMatcherSuccess($syntax, array $args = array()) { - $this->assertTrue($this->matcher->match($syntax, $args)); + $this->assert($this->matcher->match($syntax, $args)); } - /** - * @param string $assertionString - */ - protected function assertFailure($assertionString) + protected function assertFailure() { try { - $this->assert($assertionString); + call_user_func_array(array($this, 'assert'), func_get_args()); } catch(\PHPUnit_Framework_AssertionFailedError $e) { - $this->assertTrue(true); + $this->assert(true); return; } - $this->fail("Assertion '$assertionString' did not fail."); + $this->fail("Assertion did not fail."); } } diff --git a/tests/Concise/Matcher/BetweenTest.php b/tests/Concise/Matcher/BetweenTest.php new file mode 100644 index 00000000..d356ecc8 --- /dev/null +++ b/tests/Concise/Matcher/BetweenTest.php @@ -0,0 +1,39 @@ +matcher = new Between(); + } + + public function testNumberExistsBetweenTwoOtherNumbers() + { + $this->assert(123, between, 100, 'and', 150); + } + + public function testNumberIsBelowLowerBounds() + { + $this->assertFailure(80, between, 100, 'and', 150); + } + + public function testNumberIsOnTheLowerBound() + { + $this->assert(123, between, 123, 'and', 150); + } + + public function testNumberIsAboveUpperBounds() + { + $this->assertFailure(170, between, 100, 'and', 150); + } + + public function testNumberIsOnTheUpperBound() + { + $this->assert(150, between, 123, 'and', 150); + } +} diff --git a/tests/Concise/Matcher/DidNotMatchExceptionTest.php b/tests/Concise/Matcher/DidNotMatchExceptionTest.php index 66758964..d2374ca6 100644 --- a/tests/Concise/Matcher/DidNotMatchExceptionTest.php +++ b/tests/Concise/Matcher/DidNotMatchExceptionTest.php @@ -6,6 +6,6 @@ class DidNotMatchExceptionTest extends \Concise\TestCase { public function testIsATypeOfException() { - $this->assert('`new \Concise\Matcher\DidNotMatchException()` is an instance of \Exception'); + $this->assert(new DidNotMatchException(), is_an_instance_of, '\Exception'); } } diff --git a/tests/Concise/Matcher/DoesNotThrowExceptionTest.php b/tests/Concise/Matcher/DoesNotThrowExceptionTest.php index 0fee1017..864ea7cb 100644 --- a/tests/Concise/Matcher/DoesNotThrowExceptionTest.php +++ b/tests/Concise/Matcher/DoesNotThrowExceptionTest.php @@ -35,7 +35,7 @@ public function testDoesNotThrow(\Closure $method, $expectSuccess) catch(DidNotMatchException $e) { $success = false; } - $this->assertSame($expectSuccess, !$success); + $this->assert($expectSuccess, equals, !$success); } public function testDoesNotThrowMessage() @@ -45,7 +45,7 @@ public function testDoesNotThrowMessage() $this->fail("Exception was not thrown."); } catch(DidNotMatchException $e) { - $this->assertEquals("Expected exception not to be thrown.", $e->getMessage()); + $this->assert("Expected exception not to be thrown.", equals, $e->getMessage()); } } diff --git a/tests/Concise/Matcher/HasItemTest.php b/tests/Concise/Matcher/HasItemTest.php new file mode 100644 index 00000000..bdc8c194 --- /dev/null +++ b/tests/Concise/Matcher/HasItemTest.php @@ -0,0 +1,32 @@ +matcher = new HasItem(); + } + + public function testKeyValuePairExists() + { + $this->assert(array("foo" => 123), has_key, "foo", with_value, 123); + } + + public function testAlternativeSyntaxForItemExists() + { + $this->assert(array("foo" => 123), has_item, array("foo" => 123)); + } + + public function testItemDoesNotExist() + { + $this->assertFailure(array("foo" => 123), has_item, array("foo" => 124)); + } + + public function testItemExistsInMultipleItems() + { + $this->assert(array("foo" => 123, "bar" => "baz"), has_key, "foo", with_value, 123); + } +} diff --git a/tests/Concise/Matcher/HasItemsTest.php b/tests/Concise/Matcher/HasItemsTest.php new file mode 100644 index 00000000..74720cfa --- /dev/null +++ b/tests/Concise/Matcher/HasItemsTest.php @@ -0,0 +1,42 @@ +matcher = new HasItems(); + } + + public function testZeroItemsWillAlwaysMatch() + { + $this->assert(array("foo" => 123), has_items, array()); + } + + public function testSingleItemIsInSet() + { + $this->assert(array("foo" => 123), has_items, array("foo" => 123)); + } + + public function testSingleItemIsNotInSet() + { + $this->assertFailure(array("foo" => 123), has_items, array("foo" => 124)); + } + + public function testAllItemsAreInSet() + { + $this->assert(array("foo" => 123, "bar" => "baz"), has_items, array("foo" => 123, "bar" => "baz")); + } + + public function testAllItemsAreInSubset() + { + $this->assert(array("foo" => 123, "a" => "b", "bar" => "baz"), has_items, array("foo" => 123, "bar" => "baz")); + } + + public function testSomeItemsAreInSubset() + { + $this->assertFailure(array("foo" => 123, "a" => "b", "bar" => "baz"), has_items, array("foo" => 123, "bart" => 123)); + } +} diff --git a/tests/Concise/Matcher/HasValuesTest.php b/tests/Concise/Matcher/HasValuesTest.php new file mode 100644 index 00000000..4d238c32 --- /dev/null +++ b/tests/Concise/Matcher/HasValuesTest.php @@ -0,0 +1,32 @@ +matcher = new HasKeys(); + } + + public function testArrayHasOneValue() + { + $this->assert('[123] has values [123]'); + } + + public function testArrayDoesNotContainAllValues() + { + $this->assertFailure('[123] has values [0,123]'); + } + + public function testArrayValuesCanBeInAnyOrder() + { + $this->assert('["a":123,"b":456] has values [123,456]'); + } + + public function testArrayValuesCanBeASubset() + { + $this->assert('["a":123,"b":456] has values [456]'); + } +} diff --git a/tests/Concise/Matcher/IsAnArrayTest.php b/tests/Concise/Matcher/IsAnArrayTest.php index c429206d..f67567aa 100644 --- a/tests/Concise/Matcher/IsAnArrayTest.php +++ b/tests/Concise/Matcher/IsAnArrayTest.php @@ -14,8 +14,7 @@ public function setUp() public function testIsAnArray() { - $this->x = array(); - $this->assert('x is an array'); + $this->assert('[] is an array'); } public function testIsAnArrayFailure() diff --git a/tests/Concise/Matcher/IsAnAssociativeArrayTest.php b/tests/Concise/Matcher/IsAnAssociativeArrayTest.php index 0f7d1686..cd4a0b00 100644 --- a/tests/Concise/Matcher/IsAnAssociativeArrayTest.php +++ b/tests/Concise/Matcher/IsAnAssociativeArrayTest.php @@ -14,20 +14,20 @@ public function setUp() public function testAnAssociativeArrayContainsAtLeastOneKeyThatsNotANumber() { - $this->x = array( + $x = array( "a" => 123, 0 => "foo", ); - $this->assert('x is an associative array'); + $this->assert($x, is_an_associative_array); } public function testAnArrayIsAssociativeIfAllIndexesAreIntegersButNotZeroIndexed() { - $this->x = array( + $x = array( 5 => 123, 10 => "foo", ); - $this->assert('x is an associative array'); + $this->assert($x, is_an_associative_array); } public function testAnArrayIsNotAssociativeIfZeroIndexed() diff --git a/tests/Concise/Matcher/IsAnEmptyArrayTest.php b/tests/Concise/Matcher/IsAnEmptyArrayTest.php new file mode 100644 index 00000000..f3034623 --- /dev/null +++ b/tests/Concise/Matcher/IsAnEmptyArrayTest.php @@ -0,0 +1,24 @@ +matcher = new IsAnEmptyArray(); + } + + public function testArrayWithZeroElements() + { + $this->assert(array(), is_empty_array); + } + + public function testArrayWithMoreThanZeroElements() + { + $this->assertFailure(array('a'), is_empty_array); + } +} diff --git a/tests/Concise/Matcher/IsAnObjectTest.php b/tests/Concise/Matcher/IsAnObjectTest.php index 99a3b865..10777213 100644 --- a/tests/Concise/Matcher/IsAnObjectTest.php +++ b/tests/Concise/Matcher/IsAnObjectTest.php @@ -14,8 +14,7 @@ public function setUp() public function testIsAnObject() { - $this->x = new \stdClass(); - $this->assert('x is an object'); + $this->assert(new \stdClass(), is_an_object); } public function testIsAnObjectFailure() diff --git a/tests/Concise/Matcher/IsBlankTest.php b/tests/Concise/Matcher/IsBlankTest.php new file mode 100644 index 00000000..678c18b4 --- /dev/null +++ b/tests/Concise/Matcher/IsBlankTest.php @@ -0,0 +1,22 @@ +matcher = new IsBlank(); + } + + public function testStringWithNoCharactersIsBlank() + { + $this->assert('', is_blank); + } + + public function testStringWithAtLeastOneCharacterIsNotBlank() + { + $this->assertFailure('a', is_blank); + } +} diff --git a/tests/Concise/Matcher/IsFalseTest.php b/tests/Concise/Matcher/IsFalseTest.php index 249d8f5f..4f7369de 100644 --- a/tests/Concise/Matcher/IsFalseTest.php +++ b/tests/Concise/Matcher/IsFalseTest.php @@ -14,7 +14,7 @@ public function setUp() public function testFalse() { - $this->assert('`false` is false'); + $this->assert(false, is_false); } public function testZeroIsNotFalse() @@ -34,6 +34,6 @@ public function testFloatingZeroIsNotFalse() public function testFalseFailure() { - $this->assertFailure('`true` is false'); + $this->assertFailure(true, is_false); } } diff --git a/tests/Concise/Matcher/IsGreaterThanEqualTest.php b/tests/Concise/Matcher/IsGreaterThanEqualTest.php new file mode 100644 index 00000000..52612f18 --- /dev/null +++ b/tests/Concise/Matcher/IsGreaterThanEqualTest.php @@ -0,0 +1,27 @@ +matcher = new IsGreaterThanEqual(); + } + + public function testLessThan() + { + $this->assertFailure(100, is_greater_than_or_equal_to, 200); + } + + public function testGreaterThanOrEqual() + { + $this->assert(200, is_greater_than_or_equal_to, 200); + } + + public function testGreaterThan() + { + $this->assert(300, is_greater_than_or_equal_to, 200); + } +} diff --git a/tests/Concise/Matcher/IsGreaterThanTest.php b/tests/Concise/Matcher/IsGreaterThanTest.php new file mode 100644 index 00000000..3f48c08f --- /dev/null +++ b/tests/Concise/Matcher/IsGreaterThanTest.php @@ -0,0 +1,27 @@ +matcher = new IsGreaterThan(); + } + + public function testLessThan() + { + $this->assertFailure(100, is_greater_than, 200); + } + + public function testGreaterThanOrEqual() + { + $this->assertFailure(200, is_greater_than, 200); + } + + public function testGreaterThan() + { + $this->assert(300, is_greater_than, 200); + } +} diff --git a/tests/Concise/Matcher/IsInstanceOfTest.php b/tests/Concise/Matcher/IsInstanceOfTest.php index bf19bc14..4f18e87c 100644 --- a/tests/Concise/Matcher/IsInstanceOfTest.php +++ b/tests/Concise/Matcher/IsInstanceOfTest.php @@ -12,18 +12,16 @@ public function setUp() public function testIsInstanceOfWithSameClass() { - $this->x = new self(); - $this->assert('x is an instance of \Concise\Matcher\IsInstanceOfTest'); + $this->assert(new self(), is_an_instance_of, '\Concise\Matcher\IsInstanceOfTest'); } public function testIsInstanceOfWithSuperClass() { - $this->x = new self(); - $this->assert('x instance of \Concise\Matcher\AbstractMatcherTestCase'); + $this->assert(new self(), instance_of, '\Concise\Matcher\AbstractMatcherTestCase'); } public function testIsInstanceOfFailure() { - $this->assertFailure('`new \stdClass()` is instance of \Concise\Matcher\IsInstanceOfTest'); + $this->assertFailure(new \stdClass(), is_instance_of, '\Concise\Matcher\IsInstanceOfTest'); } } diff --git a/tests/Concise/Matcher/IsLessThanEqualTest.php b/tests/Concise/Matcher/IsLessThanEqualTest.php new file mode 100644 index 00000000..4a512642 --- /dev/null +++ b/tests/Concise/Matcher/IsLessThanEqualTest.php @@ -0,0 +1,27 @@ +matcher = new IsLessThanEqual(); + } + + public function testLessThan() + { + $this->assert(100, is_less_than_or_equal_to, 200); + } + + public function testLessThanOrEqual() + { + $this->assert(200, is_less_than_or_equal_to, 200); + } + + public function testGreaterThan() + { + $this->assertFailure(300, is_less_than_or_equal_to, 200); + } +} diff --git a/tests/Concise/Matcher/IsLessThanTest.php b/tests/Concise/Matcher/IsLessThanTest.php new file mode 100644 index 00000000..96825980 --- /dev/null +++ b/tests/Concise/Matcher/IsLessThanTest.php @@ -0,0 +1,27 @@ +matcher = new IsLessThan(); + } + + public function testLessThan() + { + $this->assert(100, is_less_than, 200); + } + + public function testLessThanOrEqual() + { + $this->assertFailure(200, is_less_than, 200); + } + + public function testGreaterThan() + { + $this->assertFailure(300, is_less_than, 200); + } +} diff --git a/tests/Concise/Matcher/IsNotAnArrayTest.php b/tests/Concise/Matcher/IsNotAnArrayTest.php index 6b183519..92b90d33 100644 --- a/tests/Concise/Matcher/IsNotAnArrayTest.php +++ b/tests/Concise/Matcher/IsNotAnArrayTest.php @@ -17,7 +17,6 @@ public function testIsNotAnArray() public function testIsNotAnArrayFailure() { - $this->x = array(); - $this->assertFailure('x is not an array'); + $this->assertFailure('[] is not an array'); } } diff --git a/tests/Concise/Matcher/IsNotAnAssociativeArrayTest.php b/tests/Concise/Matcher/IsNotAnAssociativeArrayTest.php index de4d8374..2210af54 100644 --- a/tests/Concise/Matcher/IsNotAnAssociativeArrayTest.php +++ b/tests/Concise/Matcher/IsNotAnAssociativeArrayTest.php @@ -14,20 +14,20 @@ public function setUp() public function testAnAssociativeArrayContainsAtLeastOneKeyThatsNotANumber() { - $this->x = array( + $x = array( "a" => 123, 0 => "foo", ); - $this->assertFailure('x is not an associative array'); + $this->assertFailure($x, is_not_an_associative_array); } public function testAnArrayIsAssociativeIfAllIndexesAreIntegersButNotZeroIndexed() { - $this->x = array( + $x = array( 5 => 123, 10 => "foo", ); - $this->assertFailure('x is not an associative array'); + $this->assertFailure($x, is_not_an_associative_array); } public function testAnArrayIsNotAssociativeIfZeroIndexed() diff --git a/tests/Concise/Matcher/IsNotAnEmptyArrayTest.php b/tests/Concise/Matcher/IsNotAnEmptyArrayTest.php new file mode 100644 index 00000000..3760d884 --- /dev/null +++ b/tests/Concise/Matcher/IsNotAnEmptyArrayTest.php @@ -0,0 +1,24 @@ +matcher = new IsNotAnEmptyArray(); + } + + public function testArrayWithZeroElements() + { + $this->assertFailure(array(), is_not_empty_array); + } + + public function testArrayWithMoreThanZeroElements() + { + $this->assert(array('a'), is_not_empty_array); + } +} diff --git a/tests/Concise/Matcher/IsNotBlankTest.php b/tests/Concise/Matcher/IsNotBlankTest.php new file mode 100644 index 00000000..26715db8 --- /dev/null +++ b/tests/Concise/Matcher/IsNotBlankTest.php @@ -0,0 +1,22 @@ +matcher = new IsNotBlank(); + } + + public function testStringWithNoCharactersIsBlank() + { + $this->assertFailure('', is_not_blank); + } + + public function testStringWithAtLeastOneCharacterIsNotBlank() + { + $this->assert('a', is_not_blank); + } +} diff --git a/tests/Concise/Matcher/IsNotInstanceOfTest.php b/tests/Concise/Matcher/IsNotInstanceOfTest.php new file mode 100644 index 00000000..2a08442b --- /dev/null +++ b/tests/Concise/Matcher/IsNotInstanceOfTest.php @@ -0,0 +1,27 @@ +matcher = new IsNotInstanceOf(); + } + + public function testIsInstanceOfWithSameClass() + { + $this->assertFailure(new self(), is_not_an_instance_of, '\Concise\Matcher\IsNotInstanceOfTest'); + } + + public function testIsInstanceOfWithSuperClass() + { + $this->assertFailure(new self(), not_instance_of, '\Concise\Matcher\AbstractMatcherTestCase'); + } + + public function testIsInstanceOfFailure() + { + $this->assert(new \stdClass(), is_not_instance_of, '\Concise\Matcher\IsNotInstanceOfTest'); + } +} diff --git a/tests/Concise/Matcher/IsNotNullTest.php b/tests/Concise/Matcher/IsNotNullTest.php index 34704b40..b3cb5cb0 100644 --- a/tests/Concise/Matcher/IsNotNullTest.php +++ b/tests/Concise/Matcher/IsNotNullTest.php @@ -24,11 +24,11 @@ public function testABlankStringIsNotNull() public function testFalseIsNotNull() { - $this->assert('`false` is not null'); + $this->assert(false, is_not_null); } public function testIsNotNullFailure() { - $this->assertFailure('`null` is not null'); + $this->assertFailure(null, is_not_null); } } diff --git a/tests/Concise/Matcher/IsNotUniqueTest.php b/tests/Concise/Matcher/IsNotUniqueTest.php new file mode 100644 index 00000000..ca3bc51f --- /dev/null +++ b/tests/Concise/Matcher/IsNotUniqueTest.php @@ -0,0 +1,24 @@ +matcher = new IsNotUnique(); + } + + public function testArrayIsUniqueIfItContainsZeroElements() + { + $this->assertFailure(array(), is_not_unique); + } + + public function testArrayIsNotUniqueIfAnyElementsAppearMoreThanOnce() + { + $this->assert(array(123, 456, 123), is_not_unique); + } +} diff --git a/tests/Concise/Matcher/IsNullTest.php b/tests/Concise/Matcher/IsNullTest.php index 569db2fe..48b387bc 100644 --- a/tests/Concise/Matcher/IsNullTest.php +++ b/tests/Concise/Matcher/IsNullTest.php @@ -14,7 +14,7 @@ public function setUp() public function testIsNull() { - $this->assert('`null` is null'); + $this->assert(null, is_null); } public function testIsNullFailure() diff --git a/tests/Concise/Matcher/IsTrueTest.php b/tests/Concise/Matcher/IsTrueTest.php index aa5fefdd..f8d43193 100644 --- a/tests/Concise/Matcher/IsTrueTest.php +++ b/tests/Concise/Matcher/IsTrueTest.php @@ -12,7 +12,7 @@ public function setUp() public function testIsTrue() { - $this->assert('`true` is true'); + $this->assert(true, is_true); } public function testIsTrueFailure() diff --git a/tests/Concise/Matcher/IsUniqueTest.php b/tests/Concise/Matcher/IsUniqueTest.php new file mode 100644 index 00000000..4eba6e9d --- /dev/null +++ b/tests/Concise/Matcher/IsUniqueTest.php @@ -0,0 +1,24 @@ +matcher = new IsUnique(); + } + + public function testArrayIsUniqueIfItContainsZeroElements() + { + $this->assert(array(), is_unique); + } + + public function testArrayIsNotUniqueIfAnyElementsAppearMoreThanOnce() + { + $this->assertFailure(array(123, 456, 123), is_unique); + } +} diff --git a/tests/Concise/Matcher/MatchesRegularExpressionTest.php b/tests/Concise/Matcher/MatchesRegularExpressionTest.php index 312d1a74..cb1f8c9c 100644 --- a/tests/Concise/Matcher/MatchesRegularExpressionTest.php +++ b/tests/Concise/Matcher/MatchesRegularExpressionTest.php @@ -14,7 +14,7 @@ public function setUp() public function testMatchesRegularExpression() { - $this->assert('123 matches regular expression /\\d+/'); + $this->assert('"123" matches regular expression /\\d+/'); } public function testMatchesRegularExpressionFailure() diff --git a/tests/Concise/Matcher/NotBetweenTest.php b/tests/Concise/Matcher/NotBetweenTest.php new file mode 100644 index 00000000..2d89b3e5 --- /dev/null +++ b/tests/Concise/Matcher/NotBetweenTest.php @@ -0,0 +1,39 @@ +matcher = new NotBetween(); + } + + public function testNumberExistsBetweenTwoOtherNumbers() + { + $this->assertFailure(123, not_between, 100, 'and', 150); + } + + public function testNumberIsBelowLowerBounds() + { + $this->assert(80, not_between, 100, 'and', 150); + } + + public function testNumberIsOnTheLowerBound() + { + $this->assertFailure(123, not_between, 123, 'and', 150); + } + + public function testNumberIsAboveUpperBounds() + { + $this->assert(170, not_between, 100, 'and', 150); + } + + public function testNumberIsOnTheUpperBound() + { + $this->assertFailure(150, not_between, 123, 'and', 150); + } +} diff --git a/tests/Concise/Matcher/StringEndsWithTest.php b/tests/Concise/Matcher/StringEndsWithTest.php index f9f72915..8a422b5f 100644 --- a/tests/Concise/Matcher/StringEndsWithTest.php +++ b/tests/Concise/Matcher/StringEndsWithTest.php @@ -17,11 +17,6 @@ public function testBasicString() $this->assert('"abc" ends with "bc"'); } - public function testNumberSubstring() - { - $this->assert('123 ends with 23'); - } - public function testStringsAreEqual() { $this->assert('"abc" ends with "abc"'); diff --git a/tests/Concise/Matcher/StringStartsWithTest.php b/tests/Concise/Matcher/StringStartsWithTest.php index f4aa3524..cb2d0d81 100644 --- a/tests/Concise/Matcher/StringStartsWithTest.php +++ b/tests/Concise/Matcher/StringStartsWithTest.php @@ -12,11 +12,6 @@ public function setUp() $this->matcher = new StringStartsWith(); } - public function testNumberSubstring() - { - $this->assert('123 starts with 12'); - } - public function testBasicString() { $this->assert('"abc" starts with "ab"'); diff --git a/tests/Concise/Matcher/ThrowsAnythingExceptTest.php b/tests/Concise/Matcher/ThrowsAnythingExceptTest.php index bc5f05ac..0b1c6cd4 100644 --- a/tests/Concise/Matcher/ThrowsAnythingExceptTest.php +++ b/tests/Concise/Matcher/ThrowsAnythingExceptTest.php @@ -47,7 +47,7 @@ public function testThrowsAnythingExcept(\Closure $method, $expectedException, $ catch(DidNotMatchException $e) { $didThrow = true; } - $this->assertSame($expectToThrow, !$didThrow); + $this->assert($expectToThrow, equals, !$didThrow); } /** diff --git a/tests/Concise/Matcher/ThrowsExceptionTest.php b/tests/Concise/Matcher/ThrowsExceptionTest.php index 448468a2..d1365722 100644 --- a/tests/Concise/Matcher/ThrowsExceptionTest.php +++ b/tests/Concise/Matcher/ThrowsExceptionTest.php @@ -35,7 +35,7 @@ public function testThrows(\Closure $method, $expectSuccess) catch(DidNotMatchException $e) { $success = false; } - $this->assertSame($expectSuccess, $success); + $this->assert($expectSuccess, equals, $success); } public function testThrowsMessage() @@ -45,7 +45,7 @@ public function testThrowsMessage() $this->fail("Exception was not thrown."); } catch(DidNotMatchException $e) { - $this->assertEquals("Expected exception to be thrown.", $e->getMessage()); + $this->assert("Expected exception to be thrown.", equals, $e->getMessage()); } } diff --git a/tests/Concise/Mock/ClassCompilerTest.php b/tests/Concise/Mock/ClassCompilerTest.php new file mode 100644 index 00000000..5049a955 --- /dev/null +++ b/tests/Concise/Mock/ClassCompilerTest.php @@ -0,0 +1,69 @@ +assertPHP($compiler, "class DateTime_% extends \\DateTime {%}"); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage The class 'DoesntExist' is not loaded so it cannot be mocked. + */ + public function testExceptionIsThrownIfClassToBeMockedIsNotLoaded() + { + new ClassCompiler('DoesntExist'); + } + + public function testMockedClassesWillBePutIntoTheCorrectNamespace() + { + $compiler = new ClassCompiler('Concise\Mock\ClassCompilerMock1'); + $this->assertPHP($compiler, "namespace Concise\Mock; class ClassCompilerMock1_% extends \Concise\Mock\ClassCompilerMock1 {%}"); + } + + public function testInstanceCanBeReturnedFromGeneratedCode() + { + $compiler = new ClassCompiler('Concise\Mock\ClassCompilerMock1'); + $this->assert($compiler->newInstance(), instance_of, 'Concise\Mock\ClassCompilerMock1'); + } + + public function testCanGenerateMockFromAbstractClass() + { + $compiler = new ClassCompiler('Concise\Mock\ClassCompilerMock2'); + $this->assert($compiler->newInstance(), instance_of, 'Concise\Mock\ClassCompilerMock2'); + } + + public function testMultipleMocksGeneratedFromTheSameClassIsPossible() + { + $a = new ClassCompiler('Concise\Mock\ClassCompilerMock1'); + $b = new ClassCompiler('Concise\Mock\ClassCompilerMock1'); + $this->assert($a->newInstance(), is_not_exactly_equal_to, $b->newInstance()); + } + + protected function assertPHP(ClassCompiler $compiler, $php) + { + $this->assert($compiler->generateCode(), matches_regex, '/' . str_replace('%', '(.*)', preg_quote($php)) . '/'); + $compiler->newInstance(); + } + + public function testExtraBackslashesAtTheStartOfTheClassNameWillBeTrimmedOff() + { + $compiler = new ClassCompiler('\Concise\Mock\ClassCompilerMock2'); + $this->assert($compiler->newInstance(), instance_of, 'Concise\Mock\ClassCompilerMock2'); + } +} diff --git a/tests/Concise/Mock/MockBuilderFailuresTest.php b/tests/Concise/Mock/MockBuilderFailuresTest.php index 94fb5066..69fc6f99 100644 --- a/tests/Concise/Mock/MockBuilderFailuresTest.php +++ b/tests/Concise/Mock/MockBuilderFailuresTest.php @@ -9,8 +9,8 @@ class MockBuilderFailuresTest extends TestCase protected static $failures = array(); protected static $expectedFailures = array( - 'testFailedToFulfilExpectationWillThrowException' => "Expectation failed for method name is equal to when invoked 1 time(s).\nMethod was expected to be called 1 times, actually called 0 times.\n", - 'testMethodCalledWithWrongArgumentValues' => "Expectation failed for method name is equal to when invoked 1 time(s)\nParameter 0 for invocation Concise\Mock\Mock1::myMethod('bar') does not match expected value.\nFailed asserting that two strings are equal.", + 'testFailedToFulfilExpectationWillThrowException' => "0 equals 1", + 'testMethodCalledWithWrongArgumentValues' => '["bar"] exactly equals ["foo"]', ); public function testFailedToFulfilExpectationWillThrowException() @@ -31,7 +31,7 @@ public function testMethodCalledWithWrongArgumentValues() protected function onNotSuccessfulTest(\Exception $e) { self::$failures[] = $this->getName(); - $this->assertSame(self::$expectedFailures[$this->getName()], $e->getMessage()); + $this->assert(self::$expectedFailures[$this->getName()], equals, $e->getMessage()); } public static function tearDownAfterClass() diff --git a/tests/Concise/Mock/MockBuilderTest.php b/tests/Concise/Mock/MockBuilderTest.php index 1381d977..83b25a9b 100644 --- a/tests/Concise/Mock/MockBuilderTest.php +++ b/tests/Concise/Mock/MockBuilderTest.php @@ -12,13 +12,30 @@ public function myMethod() } } +abstract class Mock2 +{ + public abstract function foo(); + + public function bar() + { + return 123; + } +} + +class Mock3 +{ + public function __construct($a) + { + } +} + class MockBuilderTest extends TestCase { public function testMockCanBeCreatedFromAClassThatExists() { $mock = $this->mock('\Concise\TestCase') ->done(); - $this->assert($mock, 'instance of \Concise\TestCase'); + $this->assert($mock, instance_of, '\Concise\TestCase'); } /** @@ -35,17 +52,21 @@ public function testCanStubMethodWithAssociativeArray() $mock = $this->mock('\Concise\Mock\Mock1') ->stub(array('myMethod' => 123)) ->done(); - $this->assertSame(123, $mock->myMethod()); + $this->assert($mock->myMethod(), equals, 123); } public function testStubbingWithAnArrayCanCreateMultipleStubs() { - $mock = $this->mock('\Concise\Mock\Mock1') - ->stub(array('myMethod' => 123, 'foo' => 'bar')) + $mock = $this->mock('\Concise\Mock\Mock2') + ->stub(array('bar' => 123, 'foo' => 'bar')) ->done(); - $this->assertSame('bar', $mock->foo()); + $this->assert($mock->foo(), equals, 'bar'); } + // @test you cannot mock methods that do not exist + + // @test you can only mock methods that do not exist if there is an approproate __call + /** * @expectedException Exception * @expectedExceptionMessage stub() called with array must have at least 1 element. @@ -72,14 +93,14 @@ public function testNiceMockCanBeCreatedFromAClassThatExists() { $mock = $this->niceMock('\Concise\TestCase') ->done(); - $this->assert($mock, 'instance of \Concise\TestCase'); + $this->assert($mock, instance_of, '\Concise\TestCase'); } public function testCallingMethodThatHasNoAssociatedActionOnANiceMockWillUseOriginal() { $mock = $this->niceMock('\Concise\Mock\Mock1') ->done(); - $this->assertSame('abc', $mock->myMethod()); + $this->assert($mock->myMethod(), equals, 'abc'); } public function testCallingMethodOnNiceMockWithStub() @@ -87,7 +108,7 @@ public function testCallingMethodOnNiceMockWithStub() $mock = $this->niceMock('\Concise\Mock\Mock1') ->stub(array('myMethod' => 123)) ->done(); - $this->assertSame(123, $mock->myMethod()); + $this->assert($mock->myMethod(), equals, 123); } public function testStubsCanBeCreatedByChainingAnAction() @@ -95,7 +116,7 @@ public function testStubsCanBeCreatedByChainingAnAction() $mock = $this->mock('\Concise\Mock\Mock1') ->stub('myMethod')->andReturn(123) ->done(); - $this->assertSame(123, $mock->myMethod()); + $this->assert($mock->myMethod(), equals, 123); } public function testStubWithNoActionWillReturnNull() @@ -103,7 +124,7 @@ public function testStubWithNoActionWillReturnNull() $this->mock = $this->mock('\Concise\Mock\Mock1') ->stub('myMethod') ->done(); - $this->assertNull($this->mock->myMethod()); + $this->assert($this->mock->myMethod(), is_null); } public function testStubCanReturnNull() @@ -111,7 +132,7 @@ public function testStubCanReturnNull() $mock = $this->mock('\Concise\Mock\Mock1') ->stub('myMethod')->andReturn(null) ->done(); - $this->assertNull($mock->myMethod()); + $this->assert($mock->myMethod(), is_null); } /** @@ -198,7 +219,7 @@ public function testCanCreateAnExpectationWithArgumentValues() $mock = $this->mock('\Concise\Mock\Mock1') ->expect('myMethod')->with('foo')->andReturn('bar') ->done(); - $this->assertSame('bar', $mock->myMethod('foo')); + $this->assert($mock->myMethod('foo'), equals, 'bar'); } public function testCanUseExpectsInsteadOfExpect() @@ -213,13 +234,70 @@ public function testMockClassDefaultsToStdClass() { $mock = $this->mock() ->done(); - $this->assert($mock, 'instance of \stdClass'); + $this->assert($mock, instance_of, '\stdClass'); } public function testNiceMockClassDefaultsToStdClass() { $mock = $this->niceMock() ->done(); - $this->assert($mock, 'instance of \stdClass'); + $this->assert($mock, instance_of, '\stdClass'); + } + + public function testNiceMockCanBeCreatedFromAnAbstractClass() + { + $mock = $this->niceMock('\Concise\Mock\Mock2') + ->stub(array('foo' => 'bar')) + ->done(); + $this->assert($mock->foo(), equals, 'bar'); + } + + public function testMockSetsActualCallsToZeroWhenRuleIsCreated() + { + $this->mock('\Concise\Mock\Mock1') + ->stub(array('myMethod' => 123)) + ->done(); + + $mock = end($this->_mocks); + $this->assert(count($mock['instance']->getCallsForMethod('myMethod')), exactly_equals, 0); + } + + public function testMockSetsCalledTimesToOneWhenMethodIsCalled() + { + $mock = $this->mock('\Concise\Mock\Mock1') + ->stub(array('myMethod' => 123)) + ->done(); + + $mock->myMethod(); + + $mock = end($this->_mocks); + $this->assert(count($mock['instance']->getCallsForMethod('myMethod')), exactly_equals, 1); + } + + public function testMockSetsCalledTimesIncrementsWithMultipleCalls() + { + $mock = $this->mock('\Concise\Mock\Mock1') + ->stub(array('myMethod' => 123)) + ->done(); + + $mock->myMethod(); + $mock->myMethod(); + + $mock = end($this->_mocks); + $this->assert(count($mock['instance']->getCallsForMethod('myMethod')), exactly_equals, 2); + } + + public function testMockReceivesConstructorArguments() + { + $mock = $this->mock('\Concise\Mock\Mock3', array('foo')) + ->done(); + $this->assert($mock, instance_of, '\Concise\Mock\Mock3'); + } + + public function testNiceMockReceivesConstructorArguments() + { + $mock = $this->niceMock('\Concise\Mock\Mock3', array('foo')) + ->done(); + $this->assert($mock, instance_of, '\Concise\Mock\Mock3'); } } diff --git a/tests/Concise/Mock/PrototypeBuilderTest.php b/tests/Concise/Mock/PrototypeBuilderTest.php new file mode 100644 index 00000000..56d0af99 --- /dev/null +++ b/tests/Concise/Mock/PrototypeBuilderTest.php @@ -0,0 +1,107 @@ +builder = new PrototypeBuilder(); + } + + public function testPrototypeIsBuiltFromReflectionMethod() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'foo'); + $this->assert($this->builder->getPrototype($method), equals, 'public function foo()'); + } + + public function testWillRespectPrototypeModifiers() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'bar'); + $this->assert($this->builder->getPrototype($method), equals, 'abstract protected function bar()'); + } + + public function testWillRespectPrototypeArguments() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'baz'); + $this->assert($this->builder->getPrototype($method), equals, 'abstract protected function baz($a, $b)'); + } + + public function testWillNotReturnAbstractKeywordIfToldNotTo() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'bar'); + $this->builder->hideAbstract = true; + $this->assert($this->builder->getPrototype($method), equals, 'protected function bar()'); + } + + public function testWillRespectPrototypeArgumentTypeHinting() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'a'); + $this->assert($this->builder->getPrototype($method), equals, 'abstract protected function a(\DateTime $a)'); + } + + public function testWillRespectPrototypeArgumentDefaultValue() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'b'); + $this->assert($this->builder->getPrototype($method), equals, 'abstract protected function b($a = 123)'); + } + + public function testWillRespectPrototypeArgumentPassByReference() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'c'); + $this->assert($this->builder->getPrototype($method), equals, 'abstract protected function c(&$a)'); + } + + public function testWillNotSetADefaultValueForInternalMethods() + { + $method = new \ReflectionMethod('\DateTime', 'setTime'); + $this->assert($this->builder->getPrototype($method), equals, 'public function setTime($hour, $minute, $second = NULL)'); + } + + public function testArrayHint() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'd'); + $this->assert($this->builder->getPrototype($method), equals, 'abstract protected function d(array $a)'); + } + + public function testCallableHint() + { + if(version_compare(PHP_VERSION, '5.4.0') < 0) { + $this->markTestSkipped('callable does not apply to versions below 5.4'); + } + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'e'); + $this->assert($this->builder->getPrototype($method), equals, 'abstract protected function e(callable $a)'); + } + + public function testArrayDefaultValue() + { + $method = new \ReflectionMethod('\Concise\Mock\MyClass', 'f'); + $this->assert($this->builder->getPrototype($method), equals, "abstract protected function f(\$a = array (\n))"); + } +} diff --git a/tests/Concise/Services/AssertionBuilderTest.php b/tests/Concise/Services/AssertionBuilderTest.php index eed8b0c8..6416a513 100644 --- a/tests/Concise/Services/AssertionBuilderTest.php +++ b/tests/Concise/Services/AssertionBuilderTest.php @@ -8,9 +8,8 @@ class AssertionBuilderTest extends TestCase { public function testCanFindAssertionWithArguments() { - $builder = new AssertionBuilder(array(123, 'equals', 123)); - $assertion = $builder->getAssertion(); - assertThat($assertion->getMatcher(), instance_of, '\Concise\Matcher\Equals'); + $assertion = $this->getAssertionWithArgs(array(123, 'equals', 123)); + assert_that($assertion->getMatcher(), instance_of, '\Concise\Matcher\Equals'); } /** @@ -22,4 +21,34 @@ public function testWillThrowExceptionIfAssertionCannotBeFound() $builder = new AssertionBuilder(array('foo', 'array', 123)); $builder->getAssertion(); } + + public function testAssertionBuilderWillAcceptTrue() + { + $assertion = $this->getAssertionWithArgs(array(true)); + $this->assert($assertion->getMatcher(), instance_of, '\Concise\Matcher\True'); + } + + public function testAssertionBuilderWillAcceptFalse() + { + $assertion = $this->getAssertionWithArgs(array(false)); + $this->assert($assertion->getMatcher(), instance_of, '\Concise\Matcher\False'); + } + + public function testAssertionBuilderWillAcceptTrueFollowedByOtherArguments() + { + $assertion = $this->getAssertionWithArgs(array(true, 'is true')); + $this->assert($assertion->getMatcher(), not_instance_of, '\Concise\Matcher\True'); + } + + public function testAssertionBuilderWillAcceptFalseFollowedByOtherArguments() + { + $assertion = $this->getAssertionWithArgs(array(false, 'is false')); + $this->assert($assertion->getMatcher(), not_instance_of, '\Concise\Matcher\False'); + } + + protected function getAssertionWithArgs(array $args) + { + $builder = new AssertionBuilder($args); + return $builder->getAssertion(); + } } diff --git a/tests/Concise/Services/CharacterConverterTest.php b/tests/Concise/Services/CharacterConverterTest.php index 17a1a0b4..e2b5a06d 100644 --- a/tests/Concise/Services/CharacterConverterTest.php +++ b/tests/Concise/Services/CharacterConverterTest.php @@ -29,6 +29,6 @@ public function stringData() public function testConvertingCharacterToEscapeCharacter($letter, $outcome) { $converter = new CharacterConverter(); - assertThat($converter->convertEscapedCharacter($letter), exactly_equals, $outcome); + $this->assert($converter->convertEscapedCharacter($letter), exactly_equals, $outcome); } } diff --git a/tests/Concise/Services/ComparerTest.php b/tests/Concise/Services/ComparerTest.php deleted file mode 100644 index 2c0462dd..00000000 --- a/tests/Concise/Services/ComparerTest.php +++ /dev/null @@ -1,74 +0,0 @@ -comparer = new Comparer(); - } - - public function testAllNonspecificComparisonsUseConvertToString() - { - $convertToStringMock = $this->mock('\Concise\Services\ToStringConverter') - ->expect('convertToString')->twice() - ->done(); - $this->comparer->setConvertToString($convertToStringMock); - - $this->comparer->compare("abc", "abc"); - } - - public function testBooleansAreSupported() - { - $this->assertTrue($this->comparer->compare(true, true)); - } - - public function testNullsAreSupported() - { - $this->assertTrue($this->comparer->compare(null, null)); - } - - public function testFailureReturnsFalse() - { - $this->assertFalse($this->comparer->compare(true, false)); - } - - /** - * @param string $value - * @return ToStringConverter - */ - protected function getConvertToStringMockThatExpects($value) - { - $convertToStringMock = $this->mock('\Concise\Services\ToStringConverter') - ->expect('convertToString')->with($value) - ->done(); - return $convertToStringMock; - } - - public function testOnlyFirstArgumentNeedsToFallBackToConvertToString() - { - $this->comparer->setConvertToString($this->getConvertToStringMockThatExpects('abc')); - $this->comparer->compare("abc", true); - } - - public function testOnlySecondArgumentNeedsToFallBackToConvertToString() - { - $this->comparer->setConvertToString($this->getConvertToStringMockThatExpects('def')); - $this->comparer->compare(null, "def"); - } - - public function testComparisonsAreExact() - { - $this->assertFalse($this->comparer->compare(false, '')); - } - - public function testResourcesAreSupported() - { - $this->assertFalse($this->comparer->compare(fopen('.', 'r'), null)); - } -} diff --git a/tests/Concise/Services/DataTypeCheckerTest.php b/tests/Concise/Services/DataTypeCheckerTest.php index a449c2c3..8ae9fed3 100644 --- a/tests/Concise/Services/DataTypeCheckerTest.php +++ b/tests/Concise/Services/DataTypeCheckerTest.php @@ -18,7 +18,7 @@ public function setUp() public function testBlankAcceptsAnything() { - $this->assertSame(123, $this->dataTypeChecker->check(array(), 123)); + $this->assert($this->dataTypeChecker->check(array(), 123), exactly_equals, 123); } /** @@ -44,6 +44,10 @@ public function dataTypes() array(array("int", "float"), 1.23), array(array("regex"), new Regexp('abc')), array(array("class"), 'Concise\Syntax\Token\Regexp'), + array(array("number"), 123), + array(array("number"), 12.3), + array(array("number"), '12.3'), + array(array("bool"), true), ); } @@ -52,7 +56,7 @@ public function dataTypes() */ public function testDataTypes(array $types, $value) { - $this->assertSame($value, $this->dataTypeChecker->check($types, $value)); + $this->assert($value, exactly_equals, $this->dataTypeChecker->check($types, $value)); } /** @@ -78,7 +82,7 @@ public function testAttributesAreEvaluatedFromContext() 'foo' => 'bar', ); $this->dataTypeChecker->setContext($context); - $this->assertSame('bar', $this->dataTypeChecker->check(array('string'), new Attribute('foo'))); + $this->assert($this->dataTypeChecker->check(array('string'), new Attribute('foo')), exactly_equals, 'bar'); } /** @@ -93,22 +97,22 @@ public function testWillThrowExceptionIfAttributeDoesNotExist() public function testExcludeWithEmptyArrayAllowsAnything() { $this->dataTypeChecker->setExcludeMode(); - $this->assertSame(123, $this->dataTypeChecker->check(array(), 123)); + $this->assert($this->dataTypeChecker->check(array(), 123), equals, 123); } public function testWillTrimBackslashOffClass() { - $this->assertSame('My\Class', $this->dataTypeChecker->check(array('class'), '\My\Class')); + $this->assert($this->dataTypeChecker->check(array('class'), '\My\Class'), equals, 'My\Class'); } public function testWillNotTrimBackslashOffClassIfNotValidatingAgainstClass() { - $this->assertSame('\My\Class', $this->dataTypeChecker->check(array('string'), '\My\Class')); + $this->assert($this->dataTypeChecker->check(array('string'), '\My\Class'), equals, '\My\Class'); } public function testWillNotTrimBackslashOffClassIfAnyValueCanBeAccepted() { - $this->assertSame('\My\Class', $this->dataTypeChecker->check(array(), '\My\Class')); + $this->assert($this->dataTypeChecker->check(array(), '\My\Class'), equals, '\My\Class'); } public function testWillTrimBackslashOffClassWhenInAttribute() @@ -117,6 +121,20 @@ public function testWillTrimBackslashOffClassWhenInAttribute() 'foo' => '\Bar', ); $this->dataTypeChecker->setContext($context); - $this->assertSame('Bar', $this->dataTypeChecker->check(array('class'), new Attribute('foo'))); + $this->assert($this->dataTypeChecker->check(array('class'), new Attribute('foo')), equals, 'Bar'); + } + + public function testStringsWillBeAcceptedForRegex() + { + $this->assertSame('/a/', $this->dataTypeChecker->check(array('regex'), '/a/')); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage integer not found in regex + */ + public function testNonStringsWillNotBeAcceptedForRegex() + { + $this->dataTypeChecker->check(array('regex'), 123); } } diff --git a/tests/Concise/Services/SyntaxRendererTest.php b/tests/Concise/Services/SyntaxRendererTest.php index 19bf9fe9..3dd16531 100644 --- a/tests/Concise/Services/SyntaxRendererTest.php +++ b/tests/Concise/Services/SyntaxRendererTest.php @@ -10,6 +10,6 @@ public function testCanSubstituteValuesFromArrayIntoPlaceholders() { $renderer = new SyntaxRenderer(); $data = array(1, '2', 3.1); - assertThat('1 is "2" bla 3.1', equals, $renderer->render('? is ? bla ?', $data)); + $this->assert('1 is "2" bla 3.1', equals, $renderer->render('? is ? bla ?', $data)); } } diff --git a/tests/Concise/Services/ToStringConverterTest.php b/tests/Concise/Services/ToStringConverterTest.php deleted file mode 100644 index f004aed4..00000000 --- a/tests/Concise/Services/ToStringConverterTest.php +++ /dev/null @@ -1,106 +0,0 @@ -converter = new ToStringConverter(); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Cannot convert boolean to string. - */ - public function testWillThrowExceptionIfABooleanTrueValueIsUsed() - { - $this->converter->convertToString(true); - } - - public function testWillReturnTheExactStringUsed() - { - $this->assertSame($this->converter->convertToString('hello'), 'hello'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Cannot convert boolean to string. - */ - public function testWillThrowExceptionIfABooleanFalseValueIsUsed() - { - $this->converter->convertToString(false); - } - - public function testWillConvertANumberToAString() - { - $this->assert($this->converter->convertToString(123), 'exactly equals "123"'); - } - - public function testWillReturnTheMethodsReturnValueIfItIsCallable() - { - $this->assert($this->converter->convertToString(function () { - return 'abc'; - }), 'exactly equals "abc"'); - } - - public function testWillAlwaysReturnAStringEvenIfItHasToRecurse() - { - $this->assert($this->converter->convertToString(function () { - return function() { - return 123; - }; - }), 'exactly equals "123"'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Cannot convert NULL to string. - */ - public function testWillThrowExceptionIfANullValueIsUsed() - { - $this->converter->convertToString(null); - } - - public function testWillReturnTheExceptionMessageIfTheCallableValueThrowsAnException() - { - $this->assert($this->converter->convertToString(function () { - throw new \Exception('hi'); - }), 'exactly equals "hi"'); - } - - public function testWillRenderAnObjectAsAString() - { - $object = $this->getStub('\stdClass', array( - '__toString' => 'xyz' - )); - $this->assertSame($this->converter->convertToString($object), 'xyz'); - } - - public function testWillExpandScientificNotationToAbsoluteValue() - { - $this->assertSame($this->converter->convertToString(1.23e5), '123000'); - } - - public function testWillReturnAJsonStringForAnObjectIfIsCannotBeConvertedToAString() - { - $object = new \stdClass(); - $object->abc = 123; - $this->assertSame($this->converter->convertToString($object), '{"abc":123}'); - } - - public function testWillReturnAJsonStringForAnArray() - { - $this->assertSame($this->converter->convertToString(array(1, 'abc')), '[1,"abc"]'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Cannot convert resource to string. - */ - public function testWillThrowExceptionIfAResourceValueIsUsed() - { - $this->converter->convertToString(fopen('.', 'r')); - } -} diff --git a/tests/Concise/Services/ValueDescriptorTest.php b/tests/Concise/Services/ValueDescriptorTest.php index 64aceb68..8b153748 100644 --- a/tests/Concise/Services/ValueDescriptorTest.php +++ b/tests/Concise/Services/ValueDescriptorTest.php @@ -15,31 +15,31 @@ public function setUp() public function testDescriptionOfString() { - $this->assertSame('string', $this->descriptor->describe('abc')); + $this->assert($this->descriptor->describe('abc'), equals, 'string'); } public function testDescriptionOfInteger() { - $this->assertSame('integer', $this->descriptor->describe(123)); + $this->assert($this->descriptor->describe(123), equals, 'integer'); } public function testDescriptionOfDouble() { - $this->assertSame('double', $this->descriptor->describe(1.23)); + $this->assert($this->descriptor->describe(1.23), equals, 'double'); } public function testDescriptionOfArray() { - $this->assertSame('array', $this->descriptor->describe(array())); + $this->assert($this->descriptor->describe(array()), equals, 'array'); } public function testDescriptionOfObject() { - $this->assertSame('Concise\Services\ValueDescriptorTest', $this->descriptor->describe($this)); + $this->assert($this->descriptor->describe($this), equals, 'Concise\Services\ValueDescriptorTest'); } public function testDescriptionOfResource() { - $this->assertSame('resource', $this->descriptor->describe(fopen('.', 'r'))); + $this->assert($this->descriptor->describe(fopen('.', 'r')), equals, 'resource'); } } diff --git a/tests/Concise/Services/ValueRendererTest.php b/tests/Concise/Services/ValueRendererTest.php index 907eb9dd..7f73af9c 100644 --- a/tests/Concise/Services/ValueRendererTest.php +++ b/tests/Concise/Services/ValueRendererTest.php @@ -15,44 +15,44 @@ public function setUp() public function testIntegerValueRendersWithoutModification() { - $this->assertSame('123', $this->renderer->render(123)); + $this->assert($this->renderer->render(123), equals, 123); } public function testFloatingPointValueRendersWithoutModification() { - $this->assertSame('1.23', $this->renderer->render(1.23)); + $this->assert($this->renderer->render(1.23), equals, '1.23'); } public function testStringValueRendersWithDoubleQuotes() { - $this->assertSame('"abc"', $this->renderer->render("abc")); + $this->assert($this->renderer->render("abc"), equals, '"abc"'); } public function testArrayValueRendersAsJson() { - $this->assertSame('[123,"abc"]', $this->renderer->render(array(123, "abc"))); + $this->assert($this->renderer->render(array(123, "abc")), equals, '[123,"abc"]'); } public function testObjectValueRendersAsJson() { $obj = new \stdClass(); $obj->a = 123; - $this->assertSame('stdClass:{"a":123}', $this->renderer->render($obj)); + $this->assert($this->renderer->render($obj), equals, 'stdClass:{"a":123}'); } public function testTrueValueRendersAsTrue() { - $this->assertSame('true', $this->renderer->render(true)); + $this->assert($this->renderer->render(true), equals, 'true'); } public function testFalseValueRendersAsFalse() { - $this->assertSame('false', $this->renderer->render(false)); + $this->assert($this->renderer->render(false), equals, 'false'); } public function testNullRendersAsNull() { - $this->assertSame('null', $this->renderer->render(null)); + $this->assert($this->renderer->render(null), equals, 'null'); } public function testResourceValueRendersAsResource() @@ -64,6 +64,6 @@ public function testResourceValueRendersAsResource() public function testFunctionRendersAsString() { - $this->assertSame('function', $this->renderer->render(function() {})); + $this->assert($this->renderer->render(function() {}), equals, 'function'); } } diff --git a/tests/Concise/Syntax/LexerRegexpTest.php b/tests/Concise/Syntax/LexerRegexpTest.php index 7b4c2f25..54f23548 100644 --- a/tests/Concise/Syntax/LexerRegexpTest.php +++ b/tests/Concise/Syntax/LexerRegexpTest.php @@ -14,7 +14,7 @@ protected function expectedTokens() return array( new Token\Attribute('x'), new Token\Keyword('equals'), - new Token\Regexp('\\a'), + new Token\Regexp('/\\a/'), ); } @@ -25,6 +25,6 @@ protected function expectedSyntax() protected function expectedArguments() { - return array(new Token\Attribute('x'), new Token\Regexp('\\a')); + return array(new Token\Attribute('x'), new Token\Regexp('/\\a/')); } } diff --git a/tests/Concise/Syntax/LexerTest.php b/tests/Concise/Syntax/LexerTest.php index c5a6ef28..c73c691f 100644 --- a/tests/Concise/Syntax/LexerTest.php +++ b/tests/Concise/Syntax/LexerTest.php @@ -32,7 +32,7 @@ public function tokenData() 'string5' => array("\MyClass", new Token\Value("MyClass")), 'code1' => array("`abc`", new Token\Code("abc")), 'code2' => array("`ab\nc`", new Token\Code("ab\nc")), - 'regexp1' => array("/abc/", new Token\Regexp("abc")), + 'regexp1' => array("/abc/", new Token\Regexp("/abc/")), 'array' => array("[]", new Token\Value(array())), ); } @@ -44,28 +44,27 @@ public function testReadKeywordToken($string, $expectedToken) { $lexer = new Lexer(); $result = $lexer->parse($string); - $this->assertEquals($expectedToken, $result['tokens'][0]); + $this->assert($expectedToken, equals, $result['tokens'][0]); } public function testTokensReturnsAnArrayWithABlankString() { $lexer = new Lexer(); $result = $lexer->parse(''); - $this->assertCount(0, $result['tokens']); + $this->assert(count($result['tokens']), equals, 0); } public function testLexerIgnoresBlankTokens() { $lexer = new Lexer(); $result = $lexer->parse(' not not not not '); - $this->assertCount(4, $result['tokens']); + $this->assert(count($result['tokens']), equals, 4); } public function testTokensHaveUniqueValues() { $class = new \ReflectionClass('\Concise\Syntax\Lexer'); - $constants = $class->getConstants(); - $this->assertEquals(count($constants), count(array_unique($constants))); + $this->assert($class->getConstants(), is_unique); } public function stringData() @@ -86,7 +85,7 @@ public function testTokenizerUnderstandsStrings($string, $expected) { $lexer = new Lexer(); $result = $lexer->parse($string); - $this->assertEquals(array(new Token\Value($expected)), $result['tokens']); + $this->assert(array(new Token\Value($expected)), equals, $result['tokens']); } /** @@ -123,21 +122,21 @@ public function testLexerCanExtractExpectedTypeFromSyntax() { $lexer = new Lexer(); $result = $lexer->parse('?:int'); - $this->assertSame(array('int'), $result['arguments'][0]->getAcceptedTypes()); + $this->assert($result['arguments'][0]->getAcceptedTypes(), equals, array('int')); } public function testLexerCanExtractExpectedTypesFromSyntax() { $lexer = new Lexer(); $result = $lexer->parse('?:int,float'); - $this->assertSame(array('int', 'float'), $result['arguments'][0]->getAcceptedTypes()); + $this->assert($result['arguments'][0]->getAcceptedTypes(), equals, array('int', 'float')); } public function testLexerWillNotPutExpectedTypesInAttributeValue() { $lexer = new Lexer(); $result = $lexer->parse('?:int,float'); - $this->assertSame('?', $result['arguments'][0]->getValue()); + $this->assert($result['arguments'][0]->getValue(), equals, '?'); } /** diff --git a/tests/Concise/Syntax/LexerTestCase.php b/tests/Concise/Syntax/LexerTestCase.php index 3b636672..9d5a06cc 100644 --- a/tests/Concise/Syntax/LexerTestCase.php +++ b/tests/Concise/Syntax/LexerTestCase.php @@ -23,17 +23,17 @@ public function setUp() public function testLexerWillReturnTokensForString() { - $this->assertEquals($this->expectedTokens(), $this->parsed['tokens']); + $this->assert($this->expectedTokens(), equals, $this->parsed['tokens']); } public function testLexerWillReturnSyntaxForString() { - $this->assertEquals($this->expectedSyntax(), $this->parsed['syntax']); + $this->assert($this->expectedSyntax(), equals, $this->parsed['syntax']); } public function testLexerWillReturnArgumentsForString() { - $this->assertEquals($this->expectedArguments(), $this->parsed['arguments']); + $this->assert($this->expectedArguments(), equals, $this->parsed['arguments']); } protected abstract function expectedTokens(); diff --git a/tests/Concise/Syntax/MatcherParserTest.php b/tests/Concise/Syntax/MatcherParserTest.php index 44f7275b..25b5c898 100644 --- a/tests/Concise/Syntax/MatcherParserTest.php +++ b/tests/Concise/Syntax/MatcherParserTest.php @@ -3,6 +3,7 @@ namespace Concise\Syntax; use \Concise\TestCase; +use \Concise\Services\MatcherSyntaxAndDescription; class MatcherParserStub extends MatcherParser { @@ -26,45 +27,18 @@ public function setUp() public function testCompileReturnsAssertion() { $this->parser->registerMatcher(new \Concise\Matcher\Equals()); - $this->matcher = $this->parser->compile('x equals y', $this->getData()); - $this->assert('`$self->matcher` is instance of \Concise\Assertion'); - } - - public function testMatcherIsRegisteredReturnsFalseIfClassIsNotRegistered() - { - $this->assertFalse($this->parser->matcherIsRegistered('\No\Such\Class')); + $matcher = $this->parser->compile('x equals y', $this->getData()); + $this->assert($matcher, is_instance_of, '\Concise\Assertion'); } public function testRegisteringANewMatcherReturnsTrue() { - $this->assertTrue($this->parser->registerMatcher(new \Concise\Matcher\Equals())); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Ambiguous syntax for 'something'. - */ - public function testThatOnlyOneMatcherCanRespondToASyntax() - { - $matcher1 = $this->getMockForAbstractClass('\Concise\Matcher\AbstractMatcher'); - $matcher1->expects($this->once()) - ->method('supportedSyntaxes') - ->will($this->returnValue(array('something'))); - - $matcher2 = $this->getMockForAbstractClass('\Concise\Matcher\AbstractMatcher'); - $matcher2->expects($this->once()) - ->method('supportedSyntaxes') - ->will($this->returnValue(array('something'))); - - $this->parser->registerMatcher($matcher1); - $this->parser->registerMatcher($matcher2); - - $this->parser->getMatcherForSyntax('something'); + $this->assert($this->parser->registerMatcher(new \Concise\Matcher\Equals())); } public function testGetInstanceIsASingleton() { - $this->assertSame(MatcherParser::getInstance(), MatcherParser::getInstance()); + $this->assert(MatcherParser::getInstance(), exactly_equals, MatcherParser::getInstance()); } /** @@ -91,31 +65,31 @@ public function testRegisterMatchersMustRegisterAtLeastOneMatcher() { $parser = new MatcherParserStub(); $parser->registerMatchers(); - $this->assertGreaterThan(0, $parser->getMatchers()); + $this->assert(count($parser->getMatchers()), greater_than, 0); } public function testGetAllKeywordsReturnsAnArray() { $keywords = MatcherParser::getInstance()->getKeywords(); - $this->assertTrue(is_array($keywords)); + $this->assert($keywords, is_an_array); } public function testGetAllKeywordsContainsKeywordsFromMatchers() { $keywords = MatcherParser::getInstance()->getKeywords(); - $this->assertContains('not', $keywords); + $this->assert($keywords, has_value, 'not'); } public function testGetAllKeywordsContainsOnlyUniqueWords() { $keywords = MatcherParser::getInstance()->getKeywords(); - $this->assertEquals(count($keywords), count(array_unique($keywords))); + $this->assert($keywords, is_unique); } public function testGetAllKeywordsDoesNotContainPlaceholders() { $keywords = MatcherParser::getInstance()->getKeywords(); - $this->assertNotContains('?', $keywords); + $this->assert($keywords, does_not_have_value, '?'); } public function testGetAllKeywordsAreSorted() @@ -123,37 +97,26 @@ public function testGetAllKeywordsAreSorted() $keywords1 = MatcherParser::getInstance()->getKeywords(); $keywords2 = MatcherParser::getInstance()->getKeywords(); sort($keywords2); - $this->assertEquals($keywords1, $keywords2); + $this->assert($keywords1, equals, $keywords2); } public function testGetKeywordsAreOnlyGeneratedOnce() { - $parser = $this->getMock('\Concise\Syntax\MatcherParser', array('getRawKeywords')); - $parser->expects($this->once()) - ->method('getRawKeywords') - ->will($this->returnValue(array('a'))); + $parser = $this->niceMock('\Concise\Syntax\MatcherParser') + ->expect('getRawKeywords')->once()->andReturn(array('a')) + ->done(); $parser->getKeywords(); $parser->getKeywords(); } - /** - * @param string[] $needles - */ - protected function assertArrayContains($needles, $haystack) - { - foreach($needles as $needle) { - $this->assertContains($needle, $haystack); - } - } - public function testGetAllSyntaxesContainsItemsFromDifferentMatchers() { $syntaxes = MatcherParser::getInstance()->getAllSyntaxes(); - $this->assertArrayContains(array( + $this->assert($syntaxes, has_items, array( '? is null' => 'Assert a value is null.', '? is equal to ?' => 'Assert values with no regard to exact data types.', - ), $syntaxes); + )); } public function testCanMatchSyntaxWithExpectedTypes() @@ -161,7 +124,7 @@ public function testCanMatchSyntaxWithExpectedTypes() $matcher = $this->getAbstractMatcherMockWithSupportedSyntaxes(array('?:int foobar ?:float')); $this->parser->registerMatcher($matcher); $assertion = $this->parser->compile('123 foobar 1.23', array()); - $this->assertSame($matcher, $assertion->getMatcher()); + $this->assert($matcher, exactly_equals, $assertion->getMatcher()); } /** @@ -177,7 +140,7 @@ public function testAnythingThatStartsWithAQuestionMarkWillNotBeConsideredAKeywo { $matcher = $this->getAbstractMatcherMockWithSupportedSyntaxes(array('?:int foobar ?:float')); $this->parser->registerMatcher($matcher); - $this->assertEquals(array('foobar'), $this->parser->getKeywords()); + $this->assert($this->parser->getKeywords(), equals, array('foobar')); } /** @@ -185,11 +148,9 @@ public function testAnythingThatStartsWithAQuestionMarkWillNotBeConsideredAKeywo */ protected function getAbstractMatcherMockWithSupportedSyntaxes($supportedSyntaxes) { - $matcher = $this->getMockForAbstractClass('\Concise\Matcher\AbstractMatcher'); - $matcher->expects($this->any()) - ->method('supportedSyntaxes') - ->will($this->returnValue($supportedSyntaxes)); - return $matcher; + return $this->mock('\Concise\Matcher\AbstractMatcher') + ->stub(array('supportedSyntaxes' => $supportedSyntaxes)) + ->done(); } public function testKeywordCacheIsDroppedWhenAMatcherIsAdded() @@ -200,6 +161,18 @@ public function testKeywordCacheIsDroppedWhenAMatcherIsAdded() $keywords1 = $this->parser->getKeywords(); $this->parser->registerMatcher($matcher2); $keywords2 = $this->parser->getKeywords(); - $this->assertNotEquals($keywords1, $keywords2); + $this->assert($keywords1, does_not_equal, $keywords2); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Syntax 'foo' is already declared. + */ + public function testAddingAMatcherWithDuplicateSyntaxThrowsException() + { + $matcher1 = $this->getAbstractMatcherMockWithSupportedSyntaxes(array('foo')); + $matcher2 = $this->getAbstractMatcherMockWithSupportedSyntaxes(array('foo')); + $this->parser->registerMatcher($matcher1); + $this->parser->registerMatcher($matcher2); } } diff --git a/tests/Concise/Syntax/TokenTest.php b/tests/Concise/Syntax/TokenTest.php index 458e34ea..b895e24f 100644 --- a/tests/Concise/Syntax/TokenTest.php +++ b/tests/Concise/Syntax/TokenTest.php @@ -9,18 +9,18 @@ class TokenTest extends TestCase public function testDefaultValueIsNull() { $attribute = new Token(); - $this->assertNull($attribute->getValue()); + $this->assert($attribute->getValue(), is_null); } public function testValueCanBeProvidedThroughConstructor() { $attribute = new Token\Value('abc'); - $this->assertEquals('abc', $attribute->getValue()); + $this->assert($attribute->getValue(), equals, 'abc'); } public function testRenderAsStringUsesValue() { $attribute = new Token\Value('abc'); - $this->assertEquals('abc', (string) $attribute); + $this->assert((string) $attribute, equals, 'abc'); } } diff --git a/tests/Concise/TestCaseTest.php b/tests/Concise/TestCaseTest.php index 7a49a327..0bf7b26d 100644 --- a/tests/Concise/TestCaseTest.php +++ b/tests/Concise/TestCaseTest.php @@ -8,23 +8,23 @@ class TestCaseTest extends TestCase { public function testExtendsTestCase() { - $this->assert('`new \Concise\TestCase()` is an instance of \PHPUnit_Framework_TestCase'); + $this->assert(new TestCase(), is_an_instance_of, '\PHPUnit_Framework_TestCase'); } protected function assertAssertions(array $expected, array $actual) { - $this->assertEquals(count($expected), count($actual)); + $this->assert(count($actual), equals, count($expected)); $right = array(); foreach($actual as $a) { $right[] = $a->getAssertion(); } - $this->assertEquals($expected, $right); + $this->assert($right, equals, $expected); } public function testCanSetAttribute() { $this->myAttribute = 123; - $this->assertSame(123, $this->myAttribute); + $this->assert(123, exactly_equals, $this->myAttribute); } /** @@ -41,20 +41,20 @@ public function testCanExtractDataFromTest() $this->x = 123; $this->b = '456'; $data = $this->getData(); - $this->assertSame($data['x'], 123); + $this->assert($data['x'], exactly_equals, 123); } public function testCanUnsetProperty() { $this->myUniqueProperty = 123; unset($this->myUniqueProperty); - $this->assertFalse(isset($this->myUniqueProperty)); + $this->assert(isset($this->myUniqueProperty), is_false); } public function testUnsettingAnAttributeThatDoesntExistDoesNothing() { unset($this->foobar); - $this->assertFalse(isset($this->myUniqueProperty)); + $this->assert(isset($this->myUniqueProperty), is_false); } /** @@ -70,29 +70,31 @@ public function testAssigningAnAttributeThatIsAKeywordThrowsAnException() public function testDataIncludesExplicitInstanceVariables() { - $this->assertTrue(array_key_exists('mySpecialAttribute', $this->getData())); + $this->assert($this->getData(), has_key, 'mySpecialAttribute'); } public function testIssetWorksWithAttributes() { $this->x = 123; - $this->assertTrue(isset($this->x)); + $this->assert(isset($this->x)); } public function testDataIsResetBetweenTests() { - $this->assertFalse(isset($this->x)); + $this->assert(isset($this->x), is_false); } protected function getAssertionsForFixtureTests() { - $testCase = $this->getStub('\Concise\TestCase', array( - 'getRawAssertionsForMethod' => array( - 'x equals b', - 'false', - 'true', - ) - )); + $testCase = $this->niceMock('\Concise\TestCase') + ->stub(array( + 'getRawAssertionsForMethod' => array( + 'x equals b', + 'false', + 'true', + ) + )) + ->done(); return $testCase->getAssertionsForMethod('abc'); } @@ -110,12 +112,12 @@ public function testAssertionBuilder() public function testEachTestMethodSetsTheCurrentTestCaseForRawAssertKeyword() { global $_currentTestCase; - $this->assertSame($this, $_currentTestCase); + $this->assert($this, is_the_same_as, $_currentTestCase); } public function testCanUseAssertThatFunction() { - assertThat("123 equals 123"); + assert_that("123 equals 123"); } public function testConstantsForKeywordsAreInitialised() @@ -127,4 +129,41 @@ public function testConstantsForKeywordStringsAreInitialised() { $this->assertSame(exactly_equals, 'exactly equals'); } + + public function testAssertionBuilderWillBeUsedForBooleanAssertions() + { + $this->assert(true); + } + + public function testMocksAreResetInTheSetup() + { + $this->assert($this->_mocks, exactly_equals, array()); + } + + public function testCreatingAMockAddsItToTheMocks() + { + $this->mock()->done(); + $this->assert(count($this->_mocks), equals, 1); + } + + public function testCreatingANiceMockAddsItToTheMocks() + { + $this->niceMock()->done(); + $this->assert(count($this->_mocks), equals, 1); + } + + public function testCreatingMultipleMocksAddsAllToMocks() + { + $this->mock()->done(); + $this->niceMock()->done(); + $this->assert(count($this->_mocks), equals, 2); + } + + public function testCallingDoneTwiceWillGenerateTwoMocksAndBothWillBeRegistered() + { + $mockTemplate = $this->mock(); + $mockTemplate->done(); + $mockTemplate->done(); + $this->assert(count($this->_mocks), equals, 2); + } }