Pressroom template verwijderd, website naar root van repo

This commit is contained in:
2020-03-22 15:30:52 +01:00
parent 2cb6a77425
commit f3d1c41e91
7620 changed files with 0 additions and 186900 deletions

5
vendor/phpspec/prophecy/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
*.tgz
*.phar
/composer.lock
/vendor
/phpunit.xml

39
vendor/phpspec/prophecy/.travis.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
language: php
sudo: false
cache:
directories:
- $HOME/.composer/cache
branches:
except:
- /^bugfix\/.*$/
- /^feature\/.*$/
- /^optimization\/.*$/
matrix:
include:
- php: 5.3
- php: 5.4
- php: 5.5
- php: 5.6
env: DEPENDENCIES='low'
- php: 5.6
- php: 7.0
- php: 7.1
# Use the newer stack for HHVM as HHVM does not support Precise anymore since a long time and so Precise has an outdated version
- php: hhvm
sudo: required
dist: trusty
group: edge
fast_finish: true
install:
- export COMPOSER_ROOT_VERSION=dev-master
- if [ "$DEPENDENCIES" != "low" ]; then composer update; fi;
- if [ "$DEPENDENCIES" == "low" ]; then composer update --prefer-lowest; fi;
script:
- vendor/bin/phpspec run -fpretty -v
- vendor/bin/phpunit

165
vendor/phpspec/prophecy/CHANGES.md vendored Normal file
View File

@@ -0,0 +1,165 @@
1.7.0 / 2017-03-02
==================
* Add full PHP 7.1 Support (thanks @prolic)
* Allow `sebastian/comparator ^2.0` (thanks @sebastianbergmann)
* Allow `sebastian/recursion-context ^3.0` (thanks @sebastianbergmann)
* Allow `\Error` instances in `ThrowPromise` (thanks @jameshalsall)
* Support `phpspec/phpspect ^3.2` (thanks @Sam-Burns)
* Fix failing builds (thanks @Sam-Burns)
1.6.2 / 2016-11-21
==================
* Added support for detecting @method on interfaces that the class itself implements, or when the stubbed class is an interface itself (thanks @Seldaek)
* Added support for sebastian/recursion-context 2 (thanks @sebastianbergmann)
* Added testing on PHP 7.1 on Travis (thanks @danizord)
* Fixed the usage of the phpunit comparator (thanks @Anyqax)
1.6.1 / 2016-06-07
==================
* Ignored empty method names in invalid `@method` phpdoc
* Fixed the mocking of SplFileObject
* Added compatibility with phpdocumentor/reflection-docblock 3
1.6.0 / 2016-02-15
==================
* Add Variadics support (thanks @pamil)
* Add ProphecyComparator for comparing objects that need revealing (thanks @jon-acker)
* Add ApproximateValueToken (thanks @dantleech)
* Add support for 'self' and 'parent' return type (thanks @bendavies)
* Add __invoke to allowed reflectable methods list (thanks @ftrrtf)
* Updated ExportUtil to reflect the latest changes by Sebastian (thanks @jakari)
* Specify the required php version for composer (thanks @jakzal)
* Exclude 'args' in the generated backtrace (thanks @oradwell)
* Fix code generation for scalar parameters (thanks @trowski)
* Fix missing sprintf in InvalidArgumentException __construct call (thanks @emmanuelballery)
* Fix phpdoc for magic methods (thanks @Tobion)
* Fix PhpDoc for interfaces usage (thanks @ImmRanneft)
* Prevent final methods from being manually extended (thanks @kamioftea)
* Enhance exception for invalid argument to ThrowPromise (thanks @Tobion)
1.5.0 / 2015-04-27
==================
* Add support for PHP7 scalar type hints (thanks @trowski)
* Add support for PHP7 return types (thanks @trowski)
* Update internal test suite to support PHP7
1.4.1 / 2015-04-27
==================
* Fixed bug in closure-based argument tokens (#181)
1.4.0 / 2015-03-27
==================
* Fixed errors in return type phpdocs (thanks @sobit)
* Fixed stringifying of hash containing one value (thanks @avant1)
* Improved clarity of method call expectation exception (thanks @dantleech)
* Add ability to specify which argument is returned in willReturnArgument (thanks @coderbyheart)
* Add more information to MethodNotFound exceptions (thanks @ciaranmcnulty)
* Support for mocking classes with methods that return references (thanks @edsonmedina)
* Improved object comparison (thanks @whatthejeff)
* Adopted '^' in composer dependencies (thanks @GrahamCampbell)
* Fixed non-typehinted arguments being treated as optional (thanks @whatthejeff)
* Magic methods are now filtered for keywords (thanks @seagoj)
* More readable errors for failure when expecting single calls (thanks @dantleech)
1.3.1 / 2014-11-17
==================
* Fix the edge case when failed predictions weren't recorded for `getCheckedPredictions()`
1.3.0 / 2014-11-14
==================
* Add a way to get checked predictions with `MethodProphecy::getCheckedPredictions()`
* Fix HHVM compatibility
* Remove dead code (thanks @stof)
* Add support for DirectoryIterators (thanks @shanethehat)
1.2.0 / 2014-07-18
==================
* Added support for doubling magic methods documented in the class phpdoc (thanks @armetiz)
* Fixed a segfault appearing in some cases (thanks @dmoreaulf)
* Fixed the doubling of methods with typehints on non-existent classes (thanks @gquemener)
* Added support for internal classes using keywords as method names (thanks @milan)
* Added IdenticalValueToken and Argument::is (thanks @florianv)
* Removed the usage of scalar typehints in HHVM as HHVM 3 does not support them anymore in PHP code (thanks @whatthejeff)
1.1.2 / 2014-01-24
==================
* Spy automatically promotes spied method call to an expected one
1.1.1 / 2014-01-15
==================
* Added support for HHVM
1.1.0 / 2014-01-01
==================
* Changed the generated class names to use a static counter instead of a random number
* Added a clss patch for ReflectionClass::newInstance to make its argument optional consistently (thanks @docteurklein)
* Fixed mirroring of classes with typehints on non-existent classes (thanks @docteurklein)
* Fixed the support of array callables in CallbackPromise and CallbackPrediction (thanks @ciaranmcnulty)
* Added support for properties in ObjectStateToken (thanks @adrienbrault)
* Added support for mocking classes with a final constructor (thanks @ciaranmcnulty)
* Added ArrayEveryEntryToken and Argument::withEveryEntry() (thanks @adrienbrault)
* Added an exception when trying to prophesize on a final method instead of ignoring silently (thanks @docteurklein)
* Added StringContainToken and Argument::containingString() (thanks @peterjmit)
* Added ``shouldNotHaveBeenCalled`` on the MethodProphecy (thanks @ciaranmcnulty)
* Fixed the comparison of objects in ExactValuetoken (thanks @sstok)
* Deprecated ``shouldNotBeenCalled`` in favor of ``shouldNotHaveBeenCalled``
1.0.4 / 2013-08-10
==================
* Better randomness for generated class names (thanks @sstok)
* Add support for interfaces into TypeToken and Argument::type() (thanks @sstok)
* Add support for old-style (method name === class name) constructors (thanks @l310 for report)
1.0.3 / 2013-07-04
==================
* Support callable typehints (thanks @stof)
* Do not attempt to autoload arrays when generating code (thanks @MarcoDeBortoli)
* New ArrayEntryToken (thanks @kagux)
1.0.2 / 2013-05-19
==================
* Logical `AND` token added (thanks @kagux)
* Logical `NOT` token added (thanks @kagux)
* Add support for setting custom constructor arguments
* Properly stringify hashes
* Record calls that throw exceptions
* Migrate spec suite to PhpSpec 2.0
1.0.1 / 2013-04-30
==================
* Fix broken UnexpectedCallException message
* Trim AggregateException message
1.0.0 / 2013-04-29
==================
* Improve exception messages
1.0.0-BETA2 / 2013-04-03
========================
* Add more debug information to CallTimes and Call prediction exception messages
* Fix MethodNotFoundException wrong namespace (thanks @gunnarlium)
* Fix some typos in the exception messages (thanks @pborreli)
1.0.0-BETA1 / 2013-03-25
========================
* Initial release

22
vendor/phpspec/prophecy/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,22 @@
Contributing
------------
Prophecy is an open source, community-driven project. If you'd like to contribute,
feel free to do this, but remember to follow these few simple rules:
- Make your feature addition or bug fix,
- Add either specs or examples for any changes you're making (bugfixes or additions)
(please look into `spec/` folder for some examples). This is important so we don't break
it in a future version unintentionally,
- Commit your code, but do not mess with `CHANGES.md`,
Running tests
-------------
Make sure that you don't break anything with your changes by running:
```bash
$> composer install --prefer-dist
$> vendor/bin/phpspec run
$> vendor/bin/phpunit
```

23
vendor/phpspec/prophecy/LICENSE vendored Normal file
View File

@@ -0,0 +1,23 @@
Copyright (c) 2013 Konstantin Kudryashov <ever.zet@gmail.com>
Marcello Duarte <marcello.duarte@gmail.com>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

391
vendor/phpspec/prophecy/README.md vendored Normal file
View File

@@ -0,0 +1,391 @@
# Prophecy
[![Stable release](https://poser.pugx.org/phpspec/prophecy/version.svg)](https://packagist.org/packages/phpspec/prophecy)
[![Build Status](https://travis-ci.org/phpspec/prophecy.svg?branch=master)](https://travis-ci.org/phpspec/prophecy)
Prophecy is a highly opinionated yet very powerful and flexible PHP object mocking
framework. Though initially it was created to fulfil phpspec2 needs, it is flexible
enough to be used inside any testing framework out there with minimal effort.
## A simple example
```php
<?php
class UserTest extends PHPUnit_Framework_TestCase
{
private $prophet;
public function testPasswordHashing()
{
$hasher = $this->prophet->prophesize('App\Security\Hasher');
$user = new App\Entity\User($hasher->reveal());
$hasher->generateHash($user, 'qwerty')->willReturn('hashed_pass');
$user->setPassword('qwerty');
$this->assertEquals('hashed_pass', $user->getPassword());
}
protected function setup()
{
$this->prophet = new \Prophecy\Prophet;
}
protected function tearDown()
{
$this->prophet->checkPredictions();
}
}
```
## Installation
### Prerequisites
Prophecy requires PHP 5.3.3 or greater.
### Setup through composer
First, add Prophecy to the list of dependencies inside your `composer.json`:
```json
{
"require-dev": {
"phpspec/prophecy": "~1.0"
}
}
```
Then simply install it with composer:
```bash
$> composer install --prefer-dist
```
You can read more about Composer on its [official webpage](http://getcomposer.org).
## How to use it
First of all, in Prophecy every word has a logical meaning, even the name of the library
itself (Prophecy). When you start feeling that, you'll become very fluid with this
tool.
For example, Prophecy has been named that way because it concentrates on describing the future
behavior of objects with very limited knowledge about them. But as with any other prophecy,
those object prophecies can't create themselves - there should be a Prophet:
```php
$prophet = new Prophecy\Prophet;
```
The Prophet creates prophecies by *prophesizing* them:
```php
$prophecy = $prophet->prophesize();
```
The result of the `prophesize()` method call is a new object of class `ObjectProphecy`. Yes,
that's your specific object prophecy, which describes how your object would behave
in the near future. But first, you need to specify which object you're talking about,
right?
```php
$prophecy->willExtend('stdClass');
$prophecy->willImplement('SessionHandlerInterface');
```
There are 2 interesting calls - `willExtend` and `willImplement`. The first one tells
object prophecy that our object should extend specific class, the second one says that
it should implement some interface. Obviously, objects in PHP can implement multiple
interfaces, but extend only one parent class.
### Dummies
Ok, now we have our object prophecy. What can we do with it? First of all, we can get
our object *dummy* by revealing its prophecy:
```php
$dummy = $prophecy->reveal();
```
The `$dummy` variable now holds a special dummy object. Dummy objects are objects that extend
and/or implement preset classes/interfaces by overriding all their public methods. The key
point about dummies is that they do not hold any logic - they just do nothing. Any method
of the dummy will always return `null` and the dummy will never throw any exceptions.
Dummy is your friend if you don't care about the actual behavior of this double and just need
a token object to satisfy a method typehint.
You need to understand one thing - a dummy is not a prophecy. Your object prophecy is still
assigned to `$prophecy` variable and in order to manipulate with your expectations, you
should work with it. `$dummy` is a dummy - a simple php object that tries to fulfil your
prophecy.
### Stubs
Ok, now we know how to create basic prophecies and reveal dummies from them. That's
awesome if we don't care about our _doubles_ (objects that reflect originals)
interactions. If we do, we need to use *stubs* or *mocks*.
A stub is an object double, which doesn't have any expectations about the object behavior,
but when put in specific environment, behaves in specific way. Ok, I know, it's cryptic,
but bear with me for a minute. Simply put, a stub is a dummy, which depending on the called
method signature does different things (has logic). To create stubs in Prophecy:
```php
$prophecy->read('123')->willReturn('value');
```
Oh wow. We've just made an arbitrary call on the object prophecy? Yes, we did. And this
call returned us a new object instance of class `MethodProphecy`. Yep, that's a specific
method with arguments prophecy. Method prophecies give you the ability to create method
promises or predictions. We'll talk about method predictions later in the _Mocks_ section.
#### Promises
Promises are logical blocks, that represent your fictional methods in prophecy terms
and they are handled by the `MethodProphecy::will(PromiseInterface $promise)` method.
As a matter of fact, the call that we made earlier (`willReturn('value')`) is a simple
shortcut to:
```php
$prophecy->read('123')->will(new Prophecy\Promise\ReturnPromise(array('value')));
```
This promise will cause any call to our double's `read()` method with exactly one
argument - `'123'` to always return `'value'`. But that's only for this
promise, there's plenty others you can use:
- `ReturnPromise` or `->willReturn(1)` - returns a value from a method call
- `ReturnArgumentPromise` or `->willReturnArgument($index)` - returns the nth method argument from call
- `ThrowPromise` or `->willThrow` - causes the method to throw specific exception
- `CallbackPromise` or `->will($callback)` - gives you a quick way to define your own custom logic
Keep in mind, that you can always add even more promises by implementing
`Prophecy\Promise\PromiseInterface`.
#### Method prophecies idempotency
Prophecy enforces same method prophecies and, as a consequence, same promises and
predictions for the same method calls with the same arguments. This means:
```php
$methodProphecy1 = $prophecy->read('123');
$methodProphecy2 = $prophecy->read('123');
$methodProphecy3 = $prophecy->read('321');
$methodProphecy1 === $methodProphecy2;
$methodProphecy1 !== $methodProphecy3;
```
That's interesting, right? Now you might ask me how would you define more complex
behaviors where some method call changes behavior of others. In PHPUnit or Mockery
you do that by predicting how many times your method will be called. In Prophecy,
you'll use promises for that:
```php
$user->getName()->willReturn(null);
// For PHP 5.4
$user->setName('everzet')->will(function () {
$this->getName()->willReturn('everzet');
});
// For PHP 5.3
$user->setName('everzet')->will(function ($args, $user) {
$user->getName()->willReturn('everzet');
});
// Or
$user->setName('everzet')->will(function ($args) use ($user) {
$user->getName()->willReturn('everzet');
});
```
And now it doesn't matter how many times or in which order your methods are called.
What matters is their behaviors and how well you faked it.
#### Arguments wildcarding
The previous example is awesome (at least I hope it is for you), but that's not
optimal enough. We hardcoded `'everzet'` in our expectation. Isn't there a better
way? In fact there is, but it involves understanding what this `'everzet'`
actually is.
You see, even if method arguments used during method prophecy creation look
like simple method arguments, in reality they are not. They are argument token
wildcards. As a matter of fact, `->setName('everzet')` looks like a simple call just
because Prophecy automatically transforms it under the hood into:
```php
$user->setName(new Prophecy\Argument\Token\ExactValueToken('everzet'));
```
Those argument tokens are simple PHP classes, that implement
`Prophecy\Argument\Token\TokenInterface` and tell Prophecy how to compare real arguments
with your expectations. And yes, those classnames are damn big. That's why there's a
shortcut class `Prophecy\Argument`, which you can use to create tokens like that:
```php
use Prophecy\Argument;
$user->setName(Argument::exact('everzet'));
```
`ExactValueToken` is not very useful in our case as it forced us to hardcode the username.
That's why Prophecy comes bundled with a bunch of other tokens:
- `IdenticalValueToken` or `Argument::is($value)` - checks that the argument is identical to a specific value
- `ExactValueToken` or `Argument::exact($value)` - checks that the argument matches a specific value
- `TypeToken` or `Argument::type($typeOrClass)` - checks that the argument matches a specific type or
classname
- `ObjectStateToken` or `Argument::which($method, $value)` - checks that the argument method returns
a specific value
- `CallbackToken` or `Argument::that(callback)` - checks that the argument matches a custom callback
- `AnyValueToken` or `Argument::any()` - matches any argument
- `AnyValuesToken` or `Argument::cetera()` - matches any arguments to the rest of the signature
- `StringContainsToken` or `Argument::containingString($value)` - checks that the argument contains a specific string value
And you can add even more by implementing `TokenInterface` with your own custom classes.
So, let's refactor our initial `{set,get}Name()` logic with argument tokens:
```php
use Prophecy\Argument;
$user->getName()->willReturn(null);
// For PHP 5.4
$user->setName(Argument::type('string'))->will(function ($args) {
$this->getName()->willReturn($args[0]);
});
// For PHP 5.3
$user->setName(Argument::type('string'))->will(function ($args, $user) {
$user->getName()->willReturn($args[0]);
});
// Or
$user->setName(Argument::type('string'))->will(function ($args) use ($user) {
$user->getName()->willReturn($args[0]);
});
```
That's it. Now our `{set,get}Name()` prophecy will work with any string argument provided to it.
We've just described how our stub object should behave, even though the original object could have
no behavior whatsoever.
One last bit about arguments now. You might ask, what happens in case of:
```php
use Prophecy\Argument;
$user->getName()->willReturn(null);
// For PHP 5.4
$user->setName(Argument::type('string'))->will(function ($args) {
$this->getName()->willReturn($args[0]);
});
// For PHP 5.3
$user->setName(Argument::type('string'))->will(function ($args, $user) {
$user->getName()->willReturn($args[0]);
});
// Or
$user->setName(Argument::type('string'))->will(function ($args) use ($user) {
$user->getName()->willReturn($args[0]);
});
$user->setName(Argument::any())->will(function () {
});
```
Nothing. Your stub will continue behaving the way it did before. That's because of how
arguments wildcarding works. Every argument token type has a different score level, which
wildcard then uses to calculate the final arguments match score and use the method prophecy
promise that has the highest score. In this case, `Argument::type()` in case of success
scores `5` and `Argument::any()` scores `3`. So the type token wins, as does the first
`setName()` method prophecy and its promise. The simple rule of thumb - more precise token
always wins.
#### Getting stub objects
Ok, now we know how to define our prophecy method promises, let's get our stub from
it:
```php
$stub = $prophecy->reveal();
```
As you might see, the only difference between how we get dummies and stubs is that with
stubs we describe every object conversation instead of just agreeing with `null` returns
(object being *dummy*). As a matter of fact, after you define your first promise
(method call), Prophecy will force you to define all the communications - it throws
the `UnexpectedCallException` for any call you didn't describe with object prophecy before
calling it on a stub.
### Mocks
Now we know how to define doubles without behavior (dummies) and doubles with behavior, but
no expectations (stubs). What's left is doubles for which we have some expectations. These
are called mocks and in Prophecy they look almost exactly the same as stubs, except that
they define *predictions* instead of *promises* on method prophecies:
```php
$entityManager->flush()->shouldBeCalled();
```
#### Predictions
The `shouldBeCalled()` method here assigns `CallPrediction` to our method prophecy.
Predictions are a delayed behavior check for your prophecies. You see, during the entire lifetime
of your doubles, Prophecy records every single call you're making against it inside your
code. After that, Prophecy can use this collected information to check if it matches defined
predictions. You can assign predictions to method prophecies using the
`MethodProphecy::should(PredictionInterface $prediction)` method. As a matter of fact,
the `shouldBeCalled()` method we used earlier is just a shortcut to:
```php
$entityManager->flush()->should(new Prophecy\Prediction\CallPrediction());
```
It checks if your method of interest (that matches both the method name and the arguments wildcard)
was called 1 or more times. If the prediction failed then it throws an exception. When does this
check happen? Whenever you call `checkPredictions()` on the main Prophet object:
```php
$prophet->checkPredictions();
```
In PHPUnit, you would want to put this call into the `tearDown()` method. If no predictions
are defined, it would do nothing. So it won't harm to call it after every test.
There are plenty more predictions you can play with:
- `CallPrediction` or `shouldBeCalled()` - checks that the method has been called 1 or more times
- `NoCallsPrediction` or `shouldNotBeCalled()` - checks that the method has not been called
- `CallTimesPrediction` or `shouldBeCalledTimes($count)` - checks that the method has been called
`$count` times
- `CallbackPrediction` or `should($callback)` - checks the method against your own custom callback
Of course, you can always create your own custom prediction any time by implementing
`PredictionInterface`.
### Spies
The last bit of awesomeness in Prophecy is out-of-the-box spies support. As I said in the previous
section, Prophecy records every call made during the double's entire lifetime. This means
you don't need to record predictions in order to check them. You can also do it
manually by using the `MethodProphecy::shouldHave(PredictionInterface $prediction)` method:
```php
$em = $prophet->prophesize('Doctrine\ORM\EntityManager');
$controller->createUser($em->reveal());
$em->flush()->shouldHaveBeenCalled();
```
Such manipulation with doubles is called spying. And with Prophecy it just works.

50
vendor/phpspec/prophecy/composer.json vendored Normal file
View File

@@ -0,0 +1,50 @@
{
"name": "phpspec/prophecy",
"description": "Highly opinionated mocking framework for PHP 5.3+",
"keywords": ["Mock", "Stub", "Dummy", "Double", "Fake", "Spy"],
"homepage": "https://github.com/phpspec/prophecy",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
},
{
"name": "Marcello Duarte",
"email": "marcello.duarte@gmail.com"
}
],
"require": {
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
"sebastian/comparator": "^1.1|^2.0",
"doctrine/instantiator": "^1.0.2",
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
},
"require-dev": {
"phpspec/phpspec": "^2.5|^3.2",
"phpunit/phpunit": "^4.8 || ^5.6.5"
},
"autoload": {
"psr-0": {
"Prophecy\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Fixtures\\Prophecy\\": "fixtures"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Fixtures\Prophecy;
class EmptyClass
{
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Fixtures\Prophecy;
interface EmptyInterface
{
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Fixtures\Prophecy;
final class FinalClass
{
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Fixtures\Prophecy;
interface ModifierInterface
{
public function isAbstract();
public function getVisibility();
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Fixtures\Prophecy;
interface Named
{
public function getName();
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Fixtures\Prophecy;
use I\Simply;
class OptionalDepsClass
{
public function iHaveAStrangeTypeHintedArg(\I\Simply\Am\Nonexistent $class)
{
}
public function iHaveAnEvenStrangerTypeHintedArg(Simply\Am\Not $class)
{
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Fixtures\Prophecy;
class SpecialMethods
{
public function __construct()
{
}
function __destruct()
{
}
function __call($name, $arguments)
{
}
function __sleep()
{
}
function __wakeup()
{
}
function __toString()
{
return '';
}
function __invoke()
{
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Fixtures\Prophecy;
class WithArguments
{
public function methodWithArgs(array $arg_1 = array(), \ArrayAccess $arg_2, \ArrayAccess $arg_3 = null)
{
}
public function methodWithoutTypeHints($arg)
{
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Fixtures\Prophecy;
class WithCallableArgument
{
public function methodWithArgs(callable $arg_1, callable $arg_2 = null)
{
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Fixtures\Prophecy;
class WithFinalMethod
{
final public function finalImplementation()
{
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Fixtures\Prophecy;
class WithFinalVirtuallyPrivateMethod
{
final public function __toString()
{
return '';
}
final public function _getName()
{
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Fixtures\Prophecy;
abstract class WithProtectedAbstractMethod
{
abstract protected function innerDetail();
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Fixtures\Prophecy;
class WithReferences
{
public function methodWithReferenceArgument(&$arg_1, \ArrayAccess &$arg_2)
{
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Fixtures\Prophecy;
class WithReturnTypehints extends EmptyClass
{
public function getSelf(): self {
return $this;
}
public function getName(): string {
return __CLASS__;
}
public function getParent(): parent {
return $this;
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Fixtures\Prophecy;
class WithStaticMethod
{
public static function innerDetail()
{
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Fixtures\Prophecy;
class WithTypehintedVariadicArgument
{
function methodWithTypeHintedArgs(array ...$args)
{
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Fixtures\Prophecy;
class WithVariadicArgument
{
function methodWithArgs(...$args)
{
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Fixtures\Prophecy;
class WithVirtuallyPrivateMethod
{
public function __toString()
{
return '';
}
public function _getName()
{
}
public function isAbstract()
{
}
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="PhpSpec Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,128 @@
<?php
namespace spec\Prophecy\Argument;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument\Token\TokenInterface;
class ArgumentsWildcardSpec extends ObjectBehavior
{
function it_wraps_non_token_arguments_into_ExactValueToken(\stdClass $object)
{
$this->beConstructedWith(array(42, 'zet', $object));
$class = get_class($object->getWrappedObject());
$hash = spl_object_hash($object->getWrappedObject());
$this->__toString()->shouldReturn("exact(42), exact(\"zet\"), exact($class:$hash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))");
}
function it_generates_string_representation_from_all_tokens_imploded(
TokenInterface $token1,
TokenInterface $token2,
TokenInterface $token3
) {
$token1->__toString()->willReturn('token_1');
$token2->__toString()->willReturn('token_2');
$token3->__toString()->willReturn('token_3');
$this->beConstructedWith(array($token1, $token2, $token3));
$this->__toString()->shouldReturn('token_1, token_2, token_3');
}
function it_exposes_list_of_tokens(TokenInterface $token)
{
$this->beConstructedWith(array($token));
$this->getTokens()->shouldReturn(array($token));
}
function it_returns_score_of_1_if_there_are_no_tokens_and_arguments()
{
$this->beConstructedWith(array());
$this->scoreArguments(array())->shouldReturn(1);
}
function it_should_return_match_score_based_on_all_tokens_score(
TokenInterface $token1,
TokenInterface $token2,
TokenInterface $token3
) {
$token1->scoreArgument('one')->willReturn(3);
$token1->isLast()->willReturn(false);
$token2->scoreArgument(2)->willReturn(5);
$token2->isLast()->willReturn(false);
$token3->scoreArgument($obj = new \stdClass())->willReturn(10);
$token3->isLast()->willReturn(false);
$this->beConstructedWith(array($token1, $token2, $token3));
$this->scoreArguments(array('one', 2, $obj))->shouldReturn(18);
}
function it_returns_false_if_there_is_less_arguments_than_tokens(
TokenInterface $token1,
TokenInterface $token2,
TokenInterface $token3
) {
$token1->scoreArgument('one')->willReturn(3);
$token1->isLast()->willReturn(false);
$token2->scoreArgument(2)->willReturn(5);
$token2->isLast()->willReturn(false);
$token3->scoreArgument(null)->willReturn(false);
$token3->isLast()->willReturn(false);
$this->beConstructedWith(array($token1, $token2, $token3));
$this->scoreArguments(array('one', 2))->shouldReturn(false);
}
function it_returns_false_if_there_is_less_tokens_than_arguments(
TokenInterface $token1,
TokenInterface $token2,
TokenInterface $token3
) {
$token1->scoreArgument('one')->willReturn(3);
$token1->isLast()->willReturn(false);
$token2->scoreArgument(2)->willReturn(5);
$token2->isLast()->willReturn(false);
$token3->scoreArgument($obj = new \stdClass())->willReturn(10);
$token3->isLast()->willReturn(false);
$this->beConstructedWith(array($token1, $token2, $token3));
$this->scoreArguments(array('one', 2, $obj, 4))->shouldReturn(false);
}
function it_should_return_false_if_one_of_the_tokens_returns_false(
TokenInterface $token1,
TokenInterface $token2,
TokenInterface $token3
) {
$token1->scoreArgument('one')->willReturn(3);
$token1->isLast()->willReturn(false);
$token2->scoreArgument(2)->willReturn(false);
$token2->isLast()->willReturn(false);
$token3->scoreArgument($obj = new \stdClass())->willReturn(10);
$token3->isLast()->willReturn(false);
$this->beConstructedWith(array($token1, $token2, $token3));
$this->scoreArguments(array('one', 2, $obj))->shouldReturn(false);
}
function it_should_calculate_score_until_last_token(
TokenInterface $token1,
TokenInterface $token2,
TokenInterface $token3
) {
$token1->scoreArgument('one')->willReturn(3);
$token1->isLast()->willReturn(false);
$token2->scoreArgument(2)->willReturn(7);
$token2->isLast()->willReturn(true);
$token3->scoreArgument($obj = new \stdClass())->willReturn(10);
$token3->isLast()->willReturn(false);
$this->beConstructedWith(array($token1, $token2, $token3));
$this->scoreArguments(array('one', 2, $obj))->shouldReturn(10);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
class AnyValueTokenSpec extends ObjectBehavior
{
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function its_string_representation_is_star()
{
$this->__toString()->shouldReturn('*');
}
function it_scores_any_argument_as_3()
{
$this->scoreArgument(42)->shouldReturn(3);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
class AnyValuesTokenSpec extends ObjectBehavior
{
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_last()
{
$this->shouldBeLast();
}
function its_string_representation_is_star_with_followup()
{
$this->__toString()->shouldReturn('* [, ...]');
}
function it_scores_any_argument_as_2()
{
$this->scoreArgument(42)->shouldReturn(2);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class ApproximateValueTokenSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(10.12345678, 4);
}
function it_is_initializable()
{
$this->shouldHaveType('Prophecy\Argument\Token\ApproximateValueToken');
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_scores_10_if_rounded_argument_matches_rounded_value()
{
$this->scoreArgument(10.12345)->shouldReturn(10);
}
function it_does_not_score_if_rounded_argument_does_not_match_rounded_value()
{
$this->scoreArgument(10.1234)->shouldReturn(false);
}
function it_uses_a_default_precision_of_zero()
{
$this->beConstructedWith(10.7);
$this->scoreArgument(11.4)->shouldReturn(10);
}
function it_does_not_score_if_rounded_argument_is_not_numeric()
{
$this->scoreArgument('hello')->shouldReturn(false);
}
function it_has_simple_string_representation()
{
$this->__toString()->shouldBe('≅10.1235');
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
class ArrayCountTokenSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(2);
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_scores_6_if_argument_array_has_proper_count()
{
$this->scoreArgument(array(1,2))->shouldReturn(6);
}
function it_scores_6_if_argument_countable_object_has_proper_count(\Countable $countable)
{
$countable->count()->willReturn(2);
$this->scoreArgument($countable)->shouldReturn(6);
}
function it_does_not_score_if_argument_is_neither_array_nor_countable_object()
{
$this->scoreArgument('string')->shouldBe(false);
$this->scoreArgument(5)->shouldBe(false);
$this->scoreArgument(new \stdClass)->shouldBe(false);
}
function it_does_not_score_if_argument_array_has_wrong_count()
{
$this->scoreArgument(array(1))->shouldReturn(false);
}
function it_does_not_score_if_argument_countable_object_has_wrong_count(\Countable $countable)
{
$countable->count()->willReturn(3);
$this->scoreArgument($countable)->shouldReturn(false);
}
function it_has_simple_string_representation()
{
$this->__toString()->shouldBe('count(2)');
}
}

View File

@@ -0,0 +1,202 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Argument\Token\ExactValueToken;
use Prophecy\Argument\Token\TokenInterface;
use Prophecy\Exception\InvalidArgumentException;
class ArrayEntryTokenSpec extends ObjectBehavior
{
function let(TokenInterface $key, TokenInterface $value)
{
$this->beConstructedWith($key, $value);
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_holds_key_and_value($key, $value)
{
$this->getKey()->shouldBe($key);
$this->getValue()->shouldBe($value);
}
function its_string_representation_tells_that_its_an_array_containing_the_key_value_pair($key, $value)
{
$key->__toString()->willReturn('key');
$value->__toString()->willReturn('value');
$this->__toString()->shouldBe('[..., key => value, ...]');
}
function it_wraps_non_token_value_into_ExactValueToken(TokenInterface $key, \stdClass $object)
{
$this->beConstructedWith($key, $object);
$this->getValue()->shouldHaveType('\Prophecy\Argument\Token\ExactValueToken');
}
function it_wraps_non_token_key_into_ExactValueToken(\stdClass $object, TokenInterface $value)
{
$this->beConstructedWith($object, $value);
$this->getKey()->shouldHaveType('\Prophecy\Argument\Token\ExactValueToken');
}
function it_scores_array_half_of_combined_scores_from_key_and_value_tokens($key, $value)
{
$key->scoreArgument('key')->willReturn(4);
$value->scoreArgument('value')->willReturn(6);
$this->scoreArgument(array('key'=>'value'))->shouldBe(5);
}
function it_scores_traversable_object_half_of_combined_scores_from_key_and_value_tokens(
TokenInterface $key,
TokenInterface $value,
\Iterator $object
) {
$object->current()->will(function () use ($object) {
$object->valid()->willReturn(false);
return 'value';
});
$object->key()->willReturn('key');
$object->rewind()->willReturn(null);
$object->next()->willReturn(null);
$object->valid()->willReturn(true);
$key->scoreArgument('key')->willReturn(6);
$value->scoreArgument('value')->willReturn(2);
$this->scoreArgument($object)->shouldBe(4);
}
function it_throws_exception_during_scoring_of_array_accessible_object_if_key_is_not_ExactValueToken(
TokenInterface $key,
TokenInterface $value,
\ArrayAccess $object
) {
$key->__toString()->willReturn('any_token');
$this->beConstructedWith($key,$value);
$errorMessage = 'You can only use exact value tokens to match key of ArrayAccess object'.PHP_EOL.
'But you used `any_token`.';
$this->shouldThrow(new InvalidArgumentException($errorMessage))->duringScoreArgument($object);
}
function it_scores_array_accessible_object_half_of_combined_scores_from_key_and_value_tokens(
ExactValueToken $key,
TokenInterface $value,
\ArrayAccess $object
) {
$object->offsetExists('key')->willReturn(true);
$object->offsetGet('key')->willReturn('value');
$key->getValue()->willReturn('key');
$key->scoreArgument('key')->willReturn(3);
$value->scoreArgument('value')->willReturn(1);
$this->scoreArgument($object)->shouldBe(2);
}
function it_accepts_any_key_token_type_to_score_object_that_is_both_traversable_and_array_accessible(
TokenInterface $key,
TokenInterface $value,
\ArrayIterator $object
) {
$this->beConstructedWith($key, $value);
$object->current()->will(function () use ($object) {
$object->valid()->willReturn(false);
return 'value';
});
$object->key()->willReturn('key');
$object->rewind()->willReturn(null);
$object->next()->willReturn(null);
$object->valid()->willReturn(true);
$this->shouldNotThrow(new InvalidArgumentException)->duringScoreArgument($object);
}
function it_does_not_score_if_argument_is_neither_array_nor_traversable_nor_array_accessible()
{
$this->scoreArgument('string')->shouldBe(false);
$this->scoreArgument(new \stdClass)->shouldBe(false);
}
function it_does_not_score_empty_array()
{
$this->scoreArgument(array())->shouldBe(false);
}
function it_does_not_score_array_if_key_and_value_tokens_do_not_score_same_entry($key, $value)
{
$argument = array(1 => 'foo', 2 => 'bar');
$key->scoreArgument(1)->willReturn(true);
$key->scoreArgument(2)->willReturn(false);
$value->scoreArgument('foo')->willReturn(false);
$value->scoreArgument('bar')->willReturn(true);
$this->scoreArgument($argument)->shouldBe(false);
}
function it_does_not_score_traversable_object_without_entries(\Iterator $object)
{
$object->rewind()->willReturn(null);
$object->next()->willReturn(null);
$object->valid()->willReturn(false);
$this->scoreArgument($object)->shouldBe(false);
}
function it_does_not_score_traversable_object_if_key_and_value_tokens_do_not_score_same_entry(
TokenInterface $key,
TokenInterface $value,
\Iterator $object
) {
$object->current()->willReturn('foo');
$object->current()->will(function () use ($object) {
$object->valid()->willReturn(false);
return 'bar';
});
$object->key()->willReturn(1);
$object->key()->willReturn(2);
$object->rewind()->willReturn(null);
$object->next()->willReturn(null);
$object->valid()->willReturn(true);
$key->scoreArgument(1)->willReturn(true);
$key->scoreArgument(2)->willReturn(false);
$value->scoreArgument('foo')->willReturn(false);
$value->scoreArgument('bar')->willReturn(true);
$this->scoreArgument($object)->shouldBe(false);
}
function it_does_not_score_array_accessible_object_if_it_has_no_offset_with_key_token_value(
ExactValueToken $key,
\ArrayAccess $object
) {
$object->offsetExists('key')->willReturn(false);
$key->getValue()->willReturn('key');
$this->scoreArgument($object)->shouldBe(false);
}
function it_does_not_score_array_accessible_object_if_key_and_value_tokens_do_not_score_same_entry(
ExactValueToken $key,
TokenInterface $value,
\ArrayAccess $object
) {
$object->offsetExists('key')->willReturn(true);
$object->offsetGet('key')->willReturn('value');
$key->getValue()->willReturn('key');
$value->scoreArgument('value')->willReturn(false);
$key->scoreArgument('key')->willReturn(true);
$this->scoreArgument($object)->shouldBe(false);
}
function its_score_is_capped_at_8($key, $value)
{
$key->scoreArgument('key')->willReturn(10);
$value->scoreArgument('value')->willReturn(10);
$this->scoreArgument(array('key'=>'value'))->shouldBe(8);
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument\Token\TokenInterface;
class ArrayEveryEntryTokenSpec extends ObjectBehavior
{
function let(TokenInterface $value)
{
$this->beConstructedWith($value);
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_holds_value($value)
{
$this->getValue()->shouldBe($value);
}
function its_string_representation_tells_that_its_an_array_containing_only_value($value)
{
$value->__toString()->willReturn('value');
$this->__toString()->shouldBe('[value, ..., value]');
}
function it_wraps_non_token_value_into_ExactValueToken(\stdClass $stdClass)
{
$this->beConstructedWith($stdClass);
$this->getValue()->shouldHaveType('Prophecy\Argument\Token\ExactValueToken');
}
function it_does_not_score_if_argument_is_neither_array_nor_traversable()
{
$this->scoreArgument('string')->shouldBe(false);
$this->scoreArgument(new \stdClass)->shouldBe(false);
}
function it_does_not_score_empty_array()
{
$this->scoreArgument(array())->shouldBe(false);
}
function it_does_not_score_traversable_object_without_entries(\Iterator $object)
{
$object->rewind()->willReturn(null);
$object->next()->willReturn(null);
$object->valid()->willReturn(false);
$this->scoreArgument($object)->shouldBe(false);
}
function it_scores_avg_of_scores_from_value_tokens($value)
{
$value->scoreArgument('value1')->willReturn(6);
$value->scoreArgument('value2')->willReturn(3);
$this->scoreArgument(array('value1', 'value2'))->shouldBe(4.5);
}
function it_scores_false_if_entry_scores_false($value)
{
$value->scoreArgument('value1')->willReturn(6);
$value->scoreArgument('value2')->willReturn(false);
$this->scoreArgument(array('value1', 'value2'))->shouldBe(false);
}
function it_does_not_score_array_keys($value)
{
$value->scoreArgument('value')->willReturn(6);
$value->scoreArgument('key')->shouldNotBeCalled(0);
$this->scoreArgument(array('key' => 'value'))->shouldBe(6);
}
function it_scores_traversable_object_from_value_token(TokenInterface $value, \Iterator $object)
{
$object->current()->will(function ($args, $object) {
$object->valid()->willReturn(false);
return 'value';
});
$object->key()->willReturn('key');
$object->rewind()->willReturn(null);
$object->next()->willReturn(null);
$object->valid()->willReturn(true);
$value->scoreArgument('value')->willReturn(2);
$this->scoreArgument($object)->shouldBe(2);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
class CallbackTokenSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('get_class');
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_scores_7_if_argument_matches_callback()
{
$this->beConstructedWith(function ($argument) { return 2 === $argument; });
$this->scoreArgument(2)->shouldReturn(7);
}
function it_does_not_scores_if_argument_does_not_match_callback()
{
$this->beConstructedWith(function ($argument) { return 2 === $argument; });
$this->scoreArgument(5)->shouldReturn(false);
}
function its_string_representation_should_tell_that_its_callback()
{
$this->__toString()->shouldReturn('callback()');
}
}

View File

@@ -0,0 +1,152 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
class ExactValueTokenSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(42);
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_holds_value()
{
$this->getValue()->shouldReturn(42);
}
function it_scores_10_if_value_is_equal_to_argument()
{
$this->scoreArgument(42)->shouldReturn(10);
$this->scoreArgument('42')->shouldReturn(10);
}
function it_scores_10_if_value_is_an_object_and_equal_to_argument()
{
$value = new \DateTime();
$value2 = clone $value;
$this->beConstructedWith($value);
$this->scoreArgument($value2)->shouldReturn(10);
}
function it_does_not_scores_if_value_is_not_equal_to_argument()
{
$this->scoreArgument(50)->shouldReturn(false);
$this->scoreArgument(new \stdClass())->shouldReturn(false);
}
function it_does_not_scores_if_value_an_object_and_is_not_equal_to_argument()
{
$value = new ExactValueTokenFixtureB('ABC');
$value2 = new ExactValueTokenFixtureB('CBA');
$this->beConstructedWith($value);
$this->scoreArgument($value2)->shouldReturn(false);
}
function it_does_not_scores_if_value_type_and_is_not_equal_to_argument()
{
$this->beConstructedWith(false);
$this->scoreArgument(0)->shouldReturn(false);
}
function it_generates_proper_string_representation_for_integer()
{
$this->beConstructedWith(42);
$this->__toString()->shouldReturn('exact(42)');
}
function it_generates_proper_string_representation_for_string()
{
$this->beConstructedWith('some string');
$this->__toString()->shouldReturn('exact("some string")');
}
function it_generates_single_line_representation_for_multiline_string()
{
$this->beConstructedWith("some\nstring");
$this->__toString()->shouldReturn('exact("some\\nstring")');
}
function it_generates_proper_string_representation_for_double()
{
$this->beConstructedWith(42.3);
$this->__toString()->shouldReturn('exact(42.3)');
}
function it_generates_proper_string_representation_for_boolean_true()
{
$this->beConstructedWith(true);
$this->__toString()->shouldReturn('exact(true)');
}
function it_generates_proper_string_representation_for_boolean_false()
{
$this->beConstructedWith(false);
$this->__toString()->shouldReturn('exact(false)');
}
function it_generates_proper_string_representation_for_null()
{
$this->beConstructedWith(null);
$this->__toString()->shouldReturn('exact(null)');
}
function it_generates_proper_string_representation_for_empty_array()
{
$this->beConstructedWith(array());
$this->__toString()->shouldReturn('exact([])');
}
function it_generates_proper_string_representation_for_array()
{
$this->beConstructedWith(array('zet', 42));
$this->__toString()->shouldReturn('exact(["zet", 42])');
}
function it_generates_proper_string_representation_for_resource()
{
$resource = fopen(__FILE__, 'r');
$this->beConstructedWith($resource);
$this->__toString()->shouldReturn('exact(stream:'.$resource.')');
}
function it_generates_proper_string_representation_for_object(\stdClass $object)
{
$objHash = sprintf('%s:%s',
get_class($object->getWrappedObject()),
spl_object_hash($object->getWrappedObject())
);
$this->beConstructedWith($object);
$this->__toString()->shouldReturn("exact($objHash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))");
}
}
class ExactValueTokenFixtureA
{
public $errors;
}
class ExactValueTokenFixtureB extends ExactValueTokenFixtureA
{
public $errors;
public $value = null;
public function __construct($value)
{
$this->value = $value;
}
}

View File

@@ -0,0 +1,152 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class IdenticalValueTokenSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(42);
}
function it_is_initializable()
{
$this->shouldHaveType('Prophecy\Argument\Token\IdenticalValueToken');
}
function it_scores_11_if_string_value_is_identical_to_argument()
{
$this->beConstructedWith('foo');
$this->scoreArgument('foo')->shouldReturn(11);
}
function it_scores_11_if_boolean_value_is_identical_to_argument()
{
$this->beConstructedWith(false);
$this->scoreArgument(false)->shouldReturn(11);
}
function it_scores_11_if_integer_value_is_identical_to_argument()
{
$this->beConstructedWith(31);
$this->scoreArgument(31)->shouldReturn(11);
}
function it_scores_11_if_float_value_is_identical_to_argument()
{
$this->beConstructedWith(31.12);
$this->scoreArgument(31.12)->shouldReturn(11);
}
function it_scores_11_if_array_value_is_identical_to_argument()
{
$this->beConstructedWith(array('foo' => 'bar'));
$this->scoreArgument(array('foo' => 'bar'))->shouldReturn(11);
}
function it_scores_11_if_object_value_is_identical_to_argument()
{
$object = new \stdClass();
$this->beConstructedWith($object);
$this->scoreArgument($object)->shouldReturn(11);
}
function it_scores_false_if_value_is_not_identical_to_argument()
{
$this->beConstructedWith(new \stdClass());
$this->scoreArgument('foo')->shouldReturn(false);
}
function it_scores_false_if_object_value_is_not_the_same_instance_than_argument()
{
$this->beConstructedWith(new \stdClass());
$this->scoreArgument(new \stdClass())->shouldReturn(false);
}
function it_scores_false_if_integer_value_is_not_identical_to_boolean_argument()
{
$this->beConstructedWith(1);
$this->scoreArgument(true)->shouldReturn(false);
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_generates_proper_string_representation_for_integer()
{
$this->beConstructedWith(42);
$this->__toString()->shouldReturn('identical(42)');
}
function it_generates_proper_string_representation_for_string()
{
$this->beConstructedWith('some string');
$this->__toString()->shouldReturn('identical("some string")');
}
function it_generates_single_line_representation_for_multiline_string()
{
$this->beConstructedWith("some\nstring");
$this->__toString()->shouldReturn('identical("some\\nstring")');
}
function it_generates_proper_string_representation_for_double()
{
$this->beConstructedWith(42.3);
$this->__toString()->shouldReturn('identical(42.3)');
}
function it_generates_proper_string_representation_for_boolean_true()
{
$this->beConstructedWith(true);
$this->__toString()->shouldReturn('identical(true)');
}
function it_generates_proper_string_representation_for_boolean_false()
{
$this->beConstructedWith(false);
$this->__toString()->shouldReturn('identical(false)');
}
function it_generates_proper_string_representation_for_null()
{
$this->beConstructedWith(null);
$this->__toString()->shouldReturn('identical(null)');
}
function it_generates_proper_string_representation_for_empty_array()
{
$this->beConstructedWith(array());
$this->__toString()->shouldReturn('identical([])');
}
function it_generates_proper_string_representation_for_array()
{
$this->beConstructedWith(array('zet', 42));
$this->__toString()->shouldReturn('identical(["zet", 42])');
}
function it_generates_proper_string_representation_for_resource()
{
$resource = fopen(__FILE__, 'r');
$this->beConstructedWith($resource);
$this->__toString()->shouldReturn('identical(stream:'.$resource.')');
}
function it_generates_proper_string_representation_for_object($object)
{
$objHash = sprintf('%s:%s',
get_class($object->getWrappedObject()),
spl_object_hash($object->getWrappedObject())
);
$this->beConstructedWith($object);
$this->__toString()->shouldReturn("identical($objHash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))");
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Argument\Token\TokenInterface;
class LogicalAndTokenSpec extends ObjectBehavior
{
function it_implements_TokenInterface()
{
$this->beConstructedWith(array());
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->beConstructedWith(array());
$this->shouldNotBeLast();
}
function it_generates_string_representation_from_all_tokens_imploded(
TokenInterface $token1,
TokenInterface $token2,
TokenInterface $token3
) {
$token1->__toString()->willReturn('token_1');
$token2->__toString()->willReturn('token_2');
$token3->__toString()->willReturn('token_3');
$this->beConstructedWith(array($token1, $token2, $token3));
$this->__toString()->shouldReturn('bool(token_1 AND token_2 AND token_3)');
}
function it_wraps_non_token_arguments_into_ExactValueToken()
{
$this->beConstructedWith(array(15, '1985'));
$this->__toString()->shouldReturn("bool(exact(15) AND exact(\"1985\"))");
}
function it_scores_the_maximum_score_from_all_scores_returned_by_tokens(TokenInterface $token1, TokenInterface $token2)
{
$token1->scoreArgument(1)->willReturn(10);
$token2->scoreArgument(1)->willReturn(5);
$this->beConstructedWith(array($token1, $token2));
$this->scoreArgument(1)->shouldReturn(10);
}
function it_does_not_score_if_there_are_no_arguments_or_tokens()
{
$this->beConstructedWith(array());
$this->scoreArgument('any')->shouldReturn(false);
}
function it_does_not_score_if_either_of_tokens_does_not_score(TokenInterface $token1, TokenInterface $token2)
{
$token1->scoreArgument(1)->willReturn(10);
$token1->scoreArgument(2)->willReturn(false);
$token2->scoreArgument(1)->willReturn(false);
$token2->scoreArgument(2)->willReturn(10);
$this->beConstructedWith(array($token1, $token2));
$this->scoreArgument(1)->shouldReturn(false);
$this->scoreArgument(2)->shouldReturn(false);
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument\Token\TokenInterface;
class LogicalNotTokenSpec extends ObjectBehavior
{
function let(TokenInterface $token)
{
$this->beConstructedWith($token);
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_holds_originating_token($token)
{
$this->getOriginatingToken()->shouldReturn($token);
}
function it_has_simple_string_representation($token)
{
$token->__toString()->willReturn('value');
$this->__toString()->shouldBe('not(value)');
}
function it_wraps_non_token_argument_into_ExactValueToken()
{
$this->beConstructedWith(5);
$token = $this->getOriginatingToken();
$token->shouldhaveType('Prophecy\Argument\Token\ExactValueToken');
$token->getValue()->shouldBe(5);
}
function it_scores_4_if_preset_token_does_not_match_the_argument($token)
{
$token->scoreArgument('argument')->willReturn(false);
$this->scoreArgument('argument')->shouldBe(4);
}
function it_does_not_score_if_preset_token_matches_argument($token)
{
$token->scoreArgument('argument')->willReturn(5);
$this->scoreArgument('argument')->shouldBe(false);
}
function it_is_last_if_preset_token_is_last($token)
{
$token->isLast()->willReturn(true);
$this->shouldBeLast();
}
function it_is_not_last_if_preset_token_is_not_last($token)
{
$token->isLast()->willReturn(false);
$this->shouldNotBeLast();
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
class ObjectStateTokenSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('getName', 'stdClass');
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_scores_8_if_argument_object_has_specific_method_state(\ReflectionClass $reflection)
{
$reflection->getName()->willReturn('stdClass');
$this->scoreArgument($reflection)->shouldReturn(8);
}
function it_scores_8_if_argument_object_has_specific_property_state(\stdClass $class)
{
$class->getName = 'stdClass';
$this->scoreArgument($class)->shouldReturn(8);
}
function it_does_not_score_if_argument_method_state_does_not_match()
{
$value = new ObjectStateTokenFixtureB('ABC');
$value2 = new ObjectStateTokenFixtureB('CBA');
$this->beConstructedWith('getSelf', $value);
$this->scoreArgument($value2)->shouldReturn(false);
}
function it_does_not_score_if_argument_property_state_does_not_match(\stdClass $class)
{
$class->getName = 'SplFileInfo';
$this->scoreArgument($class)->shouldReturn(false);
}
function it_does_not_score_if_argument_object_does_not_have_method_or_property(ObjectStateTokenFixtureA $class)
{
$this->scoreArgument($class)->shouldReturn(false);
}
function it_does_not_score_if_argument_is_not_object()
{
$this->scoreArgument(42)->shouldReturn(false);
}
function it_has_simple_string_representation()
{
$this->__toString()->shouldReturn('state(getName(), "stdClass")');
}
}
class ObjectStateTokenFixtureA
{
public $errors;
}
class ObjectStateTokenFixtureB extends ObjectStateTokenFixtureA
{
public $errors;
public $value = null;
public function __construct($value)
{
$this->value = $value;
}
public function getSelf()
{
return $this;
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class StringContainsTokenSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('a substring');
}
function it_is_initializable()
{
$this->shouldHaveType('Prophecy\Argument\Token\StringContainsToken');
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_holds_value()
{
$this->getValue()->shouldReturn('a substring');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_scores_6_if_the_argument_contains_the_value()
{
$this->scoreArgument('Argument containing a substring')->shouldReturn(6);
}
function it_does_not_score_if_the_argument_does_not_contain_the_value()
{
$this->scoreArgument('Argument will not match')->shouldReturn(false);
}
function its_string_representation_shows_substring()
{
$this->__toString()->shouldReturn('contains("a substring")');
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace spec\Prophecy\Argument\Token;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument\Token\TokenInterface;
class TypeTokenSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('integer');
}
function it_implements_TokenInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Argument\Token\TokenInterface');
}
function it_is_not_last()
{
$this->shouldNotBeLast();
}
function it_scores_5_if_argument_matches_simple_type()
{
$this->beConstructedWith('integer');
$this->scoreArgument(42)->shouldReturn(5);
}
function it_does_not_scores_if_argument_does_not_match_simple_type()
{
$this->beConstructedWith('integer');
$this->scoreArgument(42.0)->shouldReturn(false);
}
function it_scores_5_if_argument_is_an_instance_of_specified_class(\ReflectionObject $object)
{
$this->beConstructedWith('ReflectionClass');
$this->scoreArgument($object)->shouldReturn(5);
}
function it_has_simple_string_representation()
{
$this->__toString()->shouldReturn('type(integer)');
}
function it_scores_5_if_argument_is_an_instance_of_specified_interface(TokenInterface $interface)
{
$this->beConstructedWith('Prophecy\Argument\Token\TokenInterface');
$this->scoreArgument($interface)->shouldReturn(5);
}
}

View File

@@ -0,0 +1,107 @@
<?php
namespace spec\Prophecy;
use PhpSpec\ObjectBehavior;
class ArgumentSpec extends ObjectBehavior
{
function it_has_a_shortcut_for_exact_argument_token()
{
$token = $this->exact(42);
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\ExactValueToken');
$token->getValue()->shouldReturn(42);
}
function it_has_a_shortcut_for_any_argument_token()
{
$token = $this->any();
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\AnyValueToken');
}
function it_has_a_shortcut_for_multiple_arguments_token()
{
$token = $this->cetera();
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\AnyValuesToken');
}
function it_has_a_shortcut_for_type_token()
{
$token = $this->type('integer');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\TypeToken');
}
function it_has_a_shortcut_for_callback_token()
{
$token = $this->that('get_class');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\CallbackToken');
}
function it_has_a_shortcut_for_object_state_token()
{
$token = $this->which('getName', 'everzet');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\ObjectStateToken');
}
function it_has_a_shortcut_for_logical_and_token()
{
$token = $this->allOf('integer', 5);
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\LogicalAndToken');
}
function it_has_a_shortcut_for_array_count_token()
{
$token = $this->size(5);
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\ArrayCountToken');
}
function it_has_a_shortcut_for_array_entry_token()
{
$token = $this->withEntry('key', 'value');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\ArrayEntryToken');
}
function it_has_a_shortcut_for_array_every_entry_token()
{
$token = $this->withEveryEntry('value');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\ArrayEveryEntryToken');
}
function it_has_a_shortcut_for_identical_value_token()
{
$token = $this->is('value');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\IdenticalValueToken');
}
function it_has_a_shortcut_for_array_entry_token_matching_any_key()
{
$token = $this->containing('value');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\ArrayEntryToken');
$token->getKey()->shouldHaveType('Prophecy\Argument\Token\AnyValueToken');
}
function it_has_a_shortcut_for_array_entry_token_matching_any_value()
{
$token = $this->withKey('key');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\ArrayEntryToken');
$token->getValue()->shouldHaveType('Prophecy\Argument\Token\AnyValueToken');
}
function it_has_a_shortcut_for_logical_not_token()
{
$token = $this->not('kagux');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\LogicalNotToken');
}
function it_has_a_shortcut_for_string_contains_token()
{
$token = $this->containingString('string');
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\StringContainsToken');
}
function it_has_a_shortcut_for_approximate_token()
{
$token = $this->approximate(10);
$token->shouldBeAnInstanceOf('Prophecy\Argument\Token\ApproximateValueToken');
}
}

View File

@@ -0,0 +1,180 @@
<?php
namespace spec\Prophecy\Call;
use PhpSpec\ObjectBehavior;
use Prophecy\Promise\PromiseInterface;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Argument\ArgumentsWildcard;
class CallCenterSpec extends ObjectBehavior
{
function let(ObjectProphecy $objectProphecy)
{
}
function it_records_calls_made_through_makeCall_method(ObjectProphecy $objectProphecy, ArgumentsWildcard $wildcard)
{
$wildcard->scoreArguments(array(5, 2, 3))->willReturn(10);
$objectProphecy->getMethodProphecies()->willReturn(array());
$this->makeCall($objectProphecy, 'setValues', array(5, 2, 3));
$calls = $this->findCalls('setValues', $wildcard);
$calls->shouldHaveCount(1);
$calls[0]->shouldBeAnInstanceOf('Prophecy\Call\Call');
$calls[0]->getMethodName()->shouldReturn('setValues');
$calls[0]->getArguments()->shouldReturn(array(5, 2, 3));
$calls[0]->getReturnValue()->shouldReturn(null);
}
function it_returns_null_for_any_call_through_makeCall_if_no_method_prophecies_added(
$objectProphecy
)
{
$objectProphecy->getMethodProphecies()->willReturn(array());
$this->makeCall($objectProphecy, 'setValues', array(5, 2, 3))->shouldReturn(null);
}
function it_executes_promise_of_method_prophecy_that_matches_signature_passed_to_makeCall(
$objectProphecy,
MethodProphecy $method1,
MethodProphecy $method2,
MethodProphecy $method3,
ArgumentsWildcard $arguments1,
ArgumentsWildcard $arguments2,
ArgumentsWildcard $arguments3,
PromiseInterface $promise
) {
$method1->hasReturnVoid()->willReturn(false);
$method1->getMethodName()->willReturn('getName');
$method1->getArgumentsWildcard()->willReturn($arguments1);
$arguments1->scoreArguments(array('world', 'everything'))->willReturn(false);
$method2->hasReturnVoid()->willReturn(false);
$method2->getMethodName()->willReturn('setTitle');
$method2->getArgumentsWildcard()->willReturn($arguments2);
$arguments2->scoreArguments(array('world', 'everything'))->willReturn(false);
$method3->hasReturnVoid()->willReturn(false);
$method3->getMethodName()->willReturn('getName');
$method3->getArgumentsWildcard()->willReturn($arguments3);
$method3->getPromise()->willReturn($promise);
$arguments3->scoreArguments(array('world', 'everything'))->willReturn(200);
$objectProphecy->getMethodProphecies()->willReturn(array(
'method1' => array($method1),
'method2' => array($method2, $method3)
));
$objectProphecy->getMethodProphecies('getName')->willReturn(array($method1, $method3));
$objectProphecy->reveal()->willReturn(new \stdClass());
$promise->execute(array('world', 'everything'), $objectProphecy->getWrappedObject(), $method3)->willReturn(42);
$this->makeCall($objectProphecy, 'getName', array('world', 'everything'))->shouldReturn(42);
$calls = $this->findCalls('getName', $arguments3);
$calls->shouldHaveCount(1);
$calls[0]->getReturnValue()->shouldReturn(42);
}
function it_executes_promise_of_method_prophecy_that_matches_with_highest_score_to_makeCall(
$objectProphecy,
MethodProphecy $method1,
MethodProphecy $method2,
MethodProphecy $method3,
ArgumentsWildcard $arguments1,
ArgumentsWildcard $arguments2,
ArgumentsWildcard $arguments3,
PromiseInterface $promise
) {
$method1->hasReturnVoid()->willReturn(false);
$method1->getMethodName()->willReturn('getName');
$method1->getArgumentsWildcard()->willReturn($arguments1);
$arguments1->scoreArguments(array('world', 'everything'))->willReturn(50);
$method2->hasReturnVoid()->willReturn(false);
$method2->getMethodName()->willReturn('getName');
$method2->getArgumentsWildcard()->willReturn($arguments2);
$method2->getPromise()->willReturn($promise);
$arguments2->scoreArguments(array('world', 'everything'))->willReturn(300);
$method3->hasReturnVoid()->willReturn(false);
$method3->getMethodName()->willReturn('getName');
$method3->getArgumentsWildcard()->willReturn($arguments3);
$arguments3->scoreArguments(array('world', 'everything'))->willReturn(200);
$objectProphecy->getMethodProphecies()->willReturn(array(
'method1' => array($method1),
'method2' => array($method2, $method3)
));
$objectProphecy->getMethodProphecies('getName')->willReturn(array(
$method1, $method2, $method3
));
$objectProphecy->reveal()->willReturn(new \stdClass());
$promise->execute(array('world', 'everything'), $objectProphecy->getWrappedObject(), $method2)
->willReturn('second');
$this->makeCall($objectProphecy, 'getName', array('world', 'everything'))
->shouldReturn('second');
}
function it_throws_exception_if_call_does_not_match_any_of_defined_method_prophecies(
$objectProphecy,
MethodProphecy $method,
ArgumentsWildcard $arguments
) {
$method->getMethodName()->willReturn('getName');
$method->getArgumentsWildcard()->willReturn($arguments);
$arguments->scoreArguments(array('world', 'everything'))->willReturn(false);
$arguments->__toString()->willReturn('arg1, arg2');
$objectProphecy->getMethodProphecies()->willReturn(array('method1' => array($method)));
$objectProphecy->getMethodProphecies('getName')->willReturn(array($method));
$this->shouldThrow('Prophecy\Exception\Call\UnexpectedCallException')
->duringMakeCall($objectProphecy, 'getName', array('world', 'everything'));
}
function it_returns_null_if_method_prophecy_that_matches_makeCall_arguments_has_no_promise(
$objectProphecy,
MethodProphecy $method,
ArgumentsWildcard $arguments
) {
$method->hasReturnVoid()->willReturn(false);
$method->getMethodName()->willReturn('getName');
$method->getArgumentsWildcard()->willReturn($arguments);
$method->getPromise()->willReturn(null);
$arguments->scoreArguments(array('world', 'everything'))->willReturn(100);
$objectProphecy->getMethodProphecies()->willReturn(array($method));
$objectProphecy->getMethodProphecies('getName')->willReturn(array($method));
$this->makeCall($objectProphecy, 'getName', array('world', 'everything'))
->shouldReturn(null);
}
function it_finds_recorded_calls_by_a_method_name_and_arguments_wildcard(
$objectProphecy,
ArgumentsWildcard $wildcard
) {
$objectProphecy->getMethodProphecies()->willReturn(array());
$this->makeCall($objectProphecy, 'getName', array('world'));
$this->makeCall($objectProphecy, 'getName', array('everything'));
$this->makeCall($objectProphecy, 'setName', array(42));
$wildcard->scoreArguments(array('world'))->willReturn(false);
$wildcard->scoreArguments(array('everything'))->willReturn(10);
$calls = $this->findCalls('getName', $wildcard);
$calls->shouldHaveCount(1);
$calls[0]->getMethodName()->shouldReturn('getName');
$calls[0]->getArguments()->shouldReturn(array('everything'));
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace spec\Prophecy\Call;
use PhpSpec\ObjectBehavior;
class CallSpec extends ObjectBehavior
{
function let(\Exception $exception)
{
$this->beConstructedWith('setValues', array(5, 2), 42, $exception, 'some_file.php', 23);
}
function it_exposes_method_name_through_getter()
{
$this->getMethodName()->shouldReturn('setValues');
}
function it_exposes_arguments_through_getter()
{
$this->getArguments()->shouldReturn(array(5, 2));
}
function it_exposes_return_value_through_getter()
{
$this->getReturnValue()->shouldReturn(42);
}
function it_exposes_exception_through_getter($exception)
{
$this->getException()->shouldReturn($exception);
}
function it_exposes_file_and_line_through_getter()
{
$this->getFile()->shouldReturn('some_file.php');
$this->getLine()->shouldReturn(23);
}
function it_returns_shortpath_to_callPlace()
{
$this->getCallPlace()->shouldReturn('some_file.php:23');
}
function it_returns_unknown_as_callPlace_if_no_file_or_line_provided()
{
$this->beConstructedWith('setValues', array(), 0, null, null, null);
$this->getCallPlace()->shouldReturn('unknown');
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace spec\Prophecy\Comparator;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class ClosureComparatorSpec extends ObjectBehavior
{
function it_is_comparator()
{
$this->shouldHaveType('SebastianBergmann\Comparator\Comparator');
}
function it_accepts_only_closures()
{
$this->accepts(123, 321)->shouldReturn(false);
$this->accepts('string', 'string')->shouldReturn(false);
$this->accepts(false, true)->shouldReturn(false);
$this->accepts(true, false)->shouldReturn(false);
$this->accepts((object)array(), (object)array())->shouldReturn(false);
$this->accepts(function(){}, (object)array())->shouldReturn(false);
$this->accepts(function(){}, (object)array())->shouldReturn(false);
$this->accepts(function(){}, function(){})->shouldReturn(true);
}
function it_asserts_that_all_closures_are_different()
{
$this->shouldThrow()->duringAssertEquals(function(){}, function(){});
}
function it_asserts_that_all_closures_are_different_even_if_its_the_same_closure()
{
$closure = function(){};
$this->shouldThrow()->duringAssertEquals($closure, $closure);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace spec\Prophecy\Comparator;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class FactorySpec extends ObjectBehavior
{
function it_extends_Sebastian_Comparator_Factory()
{
$this->shouldHaveType('SebastianBergmann\Comparator\Factory');
}
function it_should_have_ClosureComparator_registered()
{
$comparator = $this->getInstance()->getComparatorFor(function(){}, function(){});
$comparator->shouldHaveType('Prophecy\Comparator\ClosureComparator');
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace spec\Prophecy\Comparator;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Prophet;
class ProphecyComparatorSpec extends ObjectBehavior
{
function it_is_a_comparator()
{
$this->shouldHaveType('SebastianBergmann\Comparator\ObjectComparator');
}
function it_accepts_only_prophecy_objects()
{
$this->accepts(123, 321)->shouldReturn(false);
$this->accepts('string', 'string')->shouldReturn(false);
$this->accepts(false, true)->shouldReturn(false);
$this->accepts(true, false)->shouldReturn(false);
$this->accepts((object)array(), (object)array())->shouldReturn(false);
$this->accepts(function(){}, (object)array())->shouldReturn(false);
$this->accepts(function(){}, function(){})->shouldReturn(false);
$prophet = new Prophet();
$prophecy = $prophet->prophesize('Prophecy\Prophecy\ObjectProphecy');
$this->accepts($prophecy, $prophecy)->shouldReturn(true);
}
function it_asserts_that_an_object_is_equal_to_its_revealed_prophecy()
{
$prophet = new Prophet();
$prophecy = $prophet->prophesize('Prophecy\Prophecy\ObjectProphecy');
$this->shouldNotThrow()->duringAssertEquals($prophecy->reveal(), $prophecy);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace spec\Prophecy\Doubler\ClassPatch;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ArgumentNode;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
class DisableConstructorPatchSpec extends ObjectBehavior
{
function it_is_a_patch()
{
$this->shouldBeAnInstanceOf('Prophecy\Doubler\ClassPatch\ClassPatchInterface');
}
function its_priority_is_100()
{
$this->getPriority()->shouldReturn(100);
}
function it_supports_anything(ClassNode $node)
{
$this->supports($node)->shouldReturn(true);
}
function it_makes_all_constructor_arguments_optional(
ClassNode $class,
MethodNode $method,
ArgumentNode $arg1,
ArgumentNode $arg2
) {
$class->hasMethod('__construct')->willReturn(true);
$class->getMethod('__construct')->willReturn($method);
$method->getArguments()->willReturn(array($arg1, $arg2));
$arg1->setDefault(null)->shouldBeCalled();
$arg2->setDefault(null)->shouldBeCalled();
$method->setCode(Argument::type('string'))->shouldBeCalled();
$this->apply($class);
}
function it_creates_new_constructor_if_object_has_none(ClassNode $class)
{
$class->hasMethod('__construct')->willReturn(false);
$class->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'))
->shouldBeCalled();
$this->apply($class);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace spec\Prophecy\Doubler\ClassPatch;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
class HhvmExceptionPatchSpec extends ObjectBehavior
{
function it_is_a_patch()
{
$this->shouldBeAnInstanceOf('Prophecy\Doubler\ClassPatch\ClassPatchInterface');
}
function its_priority_is_minus_50()
{
$this->getPriority()->shouldReturn(-50);
}
function it_uses_parent_code_for_setTraceOptions(ClassNode $node, MethodNode $method, MethodNode $getterMethod)
{
$node->hasMethod('setTraceOptions')->willReturn(true);
$node->getMethod('setTraceOptions')->willReturn($method);
$node->hasMethod('getTraceOptions')->willReturn(true);
$node->getMethod('getTraceOptions')->willReturn($getterMethod);
$method->useParentCode()->shouldBeCalled();
$getterMethod->useParentCode()->shouldBeCalled();
$this->apply($node);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace spec\Prophecy\Doubler\ClassPatch;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
class KeywordPatchSpec extends ObjectBehavior
{
function it_is_a_patch()
{
$this->shouldBeAnInstanceOf('Prophecy\Doubler\ClassPatch\ClassPatchInterface');
}
function its_priority_is_49()
{
$this->getPriority()->shouldReturn(49);
}
function it_will_remove_echo_and_eval_methods(
ClassNode $node,
MethodNode $method1,
MethodNode $method2,
MethodNode $method3
) {
$node->removeMethod('eval')->shouldBeCalled();
$node->removeMethod('echo')->shouldBeCalled();
$method1->getName()->willReturn('echo');
$method2->getName()->willReturn('eval');
$method3->getName()->willReturn('notKeyword');
$node->getMethods()->willReturn(array(
'echo' => $method1,
'eval' => $method2,
'notKeyword' => $method3,
));
$this->apply($node);
}
}

View File

@@ -0,0 +1,140 @@
<?php
namespace spec\Prophecy\Doubler\ClassPatch;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
class MagicCallPatchSpec extends ObjectBehavior
{
function it_is_a_patch()
{
$this->shouldBeAnInstanceOf('Prophecy\Doubler\ClassPatch\ClassPatchInterface');
}
function it_supports_anything(ClassNode $node)
{
$this->supports($node)->shouldReturn(true);
}
function it_discovers_api_using_phpdoc(ClassNode $node)
{
$node->getParentClass()->willReturn('spec\Prophecy\Doubler\ClassPatch\MagicalApi');
$node->getInterfaces()->willReturn(array());
$node->addMethod(new MethodNode('undefinedMethod'))->shouldBeCalled();
$this->apply($node);
}
function it_ignores_existing_methods(ClassNode $node)
{
$node->getParentClass()->willReturn('spec\Prophecy\Doubler\ClassPatch\MagicalApiExtended');
$node->getInterfaces()->willReturn(array());
$node->addMethod(new MethodNode('undefinedMethod'))->shouldBeCalled();
$node->addMethod(new MethodNode('definedMethod'))->shouldNotBeCalled();
$this->apply($node);
}
function it_ignores_empty_methods_from_phpdoc(ClassNode $node)
{
$node->getParentClass()->willReturn('spec\Prophecy\Doubler\ClassPatch\MagicalApiInvalidMethodDefinition');
$node->getInterfaces()->willReturn(array());
$node->addMethod(new MethodNode(''))->shouldNotBeCalled();
$this->apply($node);
}
function it_discovers_api_using_phpdoc_from_implemented_interfaces(ClassNode $node)
{
$node->getParentClass()->willReturn('spec\Prophecy\Doubler\ClassPatch\MagicalApiImplemented');
$node->getInterfaces()->willReturn(array());
$node->addMethod(new MethodNode('implementedMethod'))->shouldBeCalled();
$this->apply($node);
}
function it_discovers_api_using_phpdoc_from_own_interfaces(ClassNode $node)
{
$node->getParentClass()->willReturn('stdClass');
$node->getInterfaces()->willReturn(array('spec\Prophecy\Doubler\ClassPatch\MagicalApiImplemented'));
$node->addMethod(new MethodNode('implementedMethod'))->shouldBeCalled();
$this->apply($node);
}
function it_discovers_api_using_phpdoc_from_extended_parent_interfaces(ClassNode $node)
{
$node->getParentClass()->willReturn('spec\Prophecy\Doubler\ClassPatch\MagicalApiImplementedExtended');
$node->getInterfaces()->willReturn(array());
$node->addMethod(new MethodNode('implementedMethod'))->shouldBeCalled();
$this->apply($node);
}
function it_has_50_priority()
{
$this->getPriority()->shouldReturn(50);
}
}
/**
* @method void undefinedMethod()
*/
class MagicalApi
{
/**
* @return void
*/
public function definedMethod()
{
}
}
/**
* @method void invalidMethodDefinition
* @method void
* @method
*/
class MagicalApiInvalidMethodDefinition
{
}
/**
* @method void undefinedMethod()
* @method void definedMethod()
*/
class MagicalApiExtended extends MagicalApi
{
}
/**
*/
class MagicalApiImplemented implements MagicalApiInterface
{
}
/**
*/
class MagicalApiImplementedExtended extends MagicalApiImplemented
{
}
/**
* @method void implementedMethod()
*/
interface MagicalApiInterface
{
}

View File

@@ -0,0 +1,79 @@
<?php
namespace spec\Prophecy\Doubler\ClassPatch;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
class ProphecySubjectPatchSpec extends ObjectBehavior
{
function it_is_a_patch()
{
$this->shouldBeAnInstanceOf('Prophecy\Doubler\ClassPatch\ClassPatchInterface');
}
function it_has_priority_of_0()
{
$this->getPriority()->shouldReturn(0);
}
function it_supports_any_class(ClassNode $node)
{
$this->supports($node)->shouldReturn(true);
}
function it_forces_class_to_implement_ProphecySubjectInterface(ClassNode $node)
{
$node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface')->shouldBeCalled();
$node->addProperty('objectProphecy', 'private')->willReturn(null);
$node->getMethods()->willReturn(array());
$node->hasMethod(Argument::any())->willReturn(false);
$node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'))->willReturn(null);
$node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'))->willReturn(null);
$this->apply($node);
}
function it_forces_all_class_methods_except_constructor_to_proxy_calls_into_prophecy_makeCall(
ClassNode $node,
MethodNode $constructor,
MethodNode $method1,
MethodNode $method2,
MethodNode $method3
) {
$node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface')->willReturn(null);
$node->addProperty('objectProphecy', 'private')->willReturn(null);
$node->hasMethod(Argument::any())->willReturn(false);
$node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'))->willReturn(null);
$node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'))->willReturn(null);
$constructor->getName()->willReturn('__construct');
$method1->getName()->willReturn('method1');
$method2->getName()->willReturn('method2');
$method3->getName()->willReturn('method3');
$method1->getReturnType()->willReturn('int');
$method2->getReturnType()->willReturn('int');
$method3->getReturnType()->willReturn('void');
$node->getMethods()->willReturn(array(
'method1' => $method1,
'method2' => $method2,
'method3' => $method3,
));
$constructor->setCode(Argument::any())->shouldNotBeCalled();
$method1->setCode('return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());')
->shouldBeCalled();
$method2->setCode('return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());')
->shouldBeCalled();
$method3->setCode('$this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());')
->shouldBeCalled();
$this->apply($node);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace spec\Prophecy\Doubler\ClassPatch;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ArgumentNode;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
class ReflectionClassNewInstancePatchSpec extends ObjectBehavior
{
function it_is_a_patch()
{
$this->shouldBeAnInstanceOf('Prophecy\Doubler\ClassPatch\ClassPatchInterface');
}
function its_priority_is_50()
{
$this->getPriority()->shouldReturn(50);
}
function it_supports_ReflectionClass_only(ClassNode $reflectionClassNode, ClassNode $anotherClassNode)
{
$reflectionClassNode->getParentClass()->willReturn('ReflectionClass');
$anotherClassNode->getParentClass()->willReturn('stdClass');
$this->supports($reflectionClassNode)->shouldReturn(true);
$this->supports($anotherClassNode)->shouldReturn(false);
}
function it_makes_all_newInstance_arguments_optional(
ClassNode $class,
MethodNode $method,
ArgumentNode $arg1
) {
$class->getMethod('newInstance')->willReturn($method);
$method->getArguments()->willReturn(array($arg1));
$arg1->setDefault(null)->shouldBeCalled();
$this->apply($class);
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace spec\Prophecy\Doubler\ClassPatch;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
class SplFileInfoPatchSpec extends ObjectBehavior
{
function it_is_a_patch()
{
$this->shouldBeAnInstanceOf('Prophecy\Doubler\ClassPatch\ClassPatchInterface');
}
function its_priority_is_50()
{
$this->getPriority()->shouldReturn(50);
}
function it_does_not_support_nodes_without_parent_class(ClassNode $node)
{
$node->getParentClass()->willReturn('stdClass');
$this->supports($node)->shouldReturn(false);
}
function it_supports_nodes_with_SplFileInfo_as_parent_class(ClassNode $node)
{
$node->getParentClass()->willReturn('SplFileInfo');
$this->supports($node)->shouldReturn(true);
}
function it_supports_nodes_with_derivative_of_SplFileInfo_as_parent_class(ClassNode $node)
{
$node->getParentClass()->willReturn('SplFileInfo');
$this->supports($node)->shouldReturn(true);
}
function it_adds_a_method_to_node_if_not_exists(ClassNode $node)
{
$node->hasMethod('__construct')->willReturn(false);
$node->addMethod(Argument::any())->shouldBeCalled();
$node->getParentClass()->shouldBeCalled();
$this->apply($node);
}
function it_updates_existing_method_if_found(ClassNode $node, MethodNode $method)
{
$node->hasMethod('__construct')->willReturn(true);
$node->getMethod('__construct')->willReturn($method);
$node->getParentClass()->shouldBeCalled();
$method->useParentCode()->shouldBeCalled();
$this->apply($node);
}
function it_should_not_supply_a_file_for_a_directory_iterator(ClassNode $node, MethodNode $method)
{
$node->hasMethod('__construct')->willReturn(true);
$node->getMethod('__construct')->willReturn($method);
$node->getParentClass()->willReturn('DirectoryIterator');
$method->setCode(Argument::that(function($value) {
return strpos($value, '.php') === false;
}))->shouldBeCalled();
$this->apply($node);
}
function it_should_supply_a_file_for_a_spl_file_object(ClassNode $node, MethodNode $method)
{
$node->hasMethod('__construct')->willReturn(true);
$node->getMethod('__construct')->willReturn($method);
$node->getParentClass()->willReturn('SplFileObject');
$method->setCode(Argument::that(function($value) {
return strpos($value, '.php') !== false;
}))->shouldBeCalled();
$this->apply($node);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace spec\Prophecy\Doubler\ClassPatch;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ClassNode;
class TraversablePatchSpec extends ObjectBehavior
{
function it_is_a_patch()
{
$this->shouldBeAnInstanceOf('Prophecy\Doubler\ClassPatch\ClassPatchInterface');
}
function it_supports_class_that_implements_only_Traversable(ClassNode $node)
{
$node->getInterfaces()->willReturn(array('Traversable'));
$this->supports($node)->shouldReturn(true);
}
function it_does_not_support_class_that_implements_Iterator(ClassNode $node)
{
$node->getInterfaces()->willReturn(array('Traversable', 'Iterator'));
$this->supports($node)->shouldReturn(false);
}
function it_does_not_support_class_that_implements_IteratorAggregate(ClassNode $node)
{
$node->getInterfaces()->willReturn(array('Traversable', 'IteratorAggregate'));
$this->supports($node)->shouldReturn(false);
}
function it_has_100_priority()
{
$this->getPriority()->shouldReturn(100);
}
function it_forces_node_to_implement_IteratorAggregate(ClassNode $node)
{
$node->addInterface('Iterator')->shouldBeCalled();
$node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'))->willReturn(null);
$this->apply($node);
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace spec\Prophecy\Doubler;
use PhpSpec\ObjectBehavior;
use Prophecy\Doubler\ClassPatch\ClassPatchInterface;
use Prophecy\Doubler\Generator\ClassCreator;
use Prophecy\Doubler\Generator\ClassMirror;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\NameGenerator;
class DoublerSpec extends ObjectBehavior
{
function let(ClassMirror $mirror, ClassCreator $creator, NameGenerator $namer)
{
$this->beConstructedWith($mirror, $creator, $namer);
}
function it_does_not_have_patches_by_default()
{
$this->getClassPatches()->shouldHaveCount(0);
}
function its_registerClassPatch_adds_a_patch_to_the_doubler(ClassPatchInterface $patch)
{
$this->registerClassPatch($patch);
$this->getClassPatches()->shouldReturn(array($patch));
}
function its_getClassPatches_sorts_patches_by_priority(
ClassPatchInterface $alt1,
ClassPatchInterface $alt2,
ClassPatchInterface $alt3,
ClassPatchInterface $alt4
) {
$alt1->getPriority()->willReturn(2);
$alt2->getPriority()->willReturn(50);
$alt3->getPriority()->willReturn(10);
$alt4->getPriority()->willReturn(0);
$this->registerClassPatch($alt1);
$this->registerClassPatch($alt2);
$this->registerClassPatch($alt3);
$this->registerClassPatch($alt4);
$this->getClassPatches()->shouldReturn(array($alt2, $alt3, $alt1, $alt4));
}
function its_double_mirrors_alterates_and_instantiates_provided_class(
$mirror,
$creator,
$namer,
ClassPatchInterface $alt1,
ClassPatchInterface $alt2,
\ReflectionClass $class,
\ReflectionClass $interface1,
\ReflectionClass $interface2,
ClassNode $node
) {
$mirror->reflect($class, array($interface1, $interface2))->willReturn($node);
$alt1->supports($node)->willReturn(true);
$alt2->supports($node)->willReturn(false);
$alt1->getPriority()->willReturn(1);
$alt2->getPriority()->willReturn(2);
$namer->name($class, array($interface1, $interface2))->willReturn('SplStack');
$class->getName()->willReturn('stdClass');
$interface1->getName()->willReturn('ArrayAccess');
$interface2->getName()->willReturn('Iterator');
$alt1->apply($node)->shouldBeCalled();
$alt2->apply($node)->shouldNotBeCalled();
$creator->create('SplStack', $node)->shouldBeCalled();
$this->registerClassPatch($alt1);
$this->registerClassPatch($alt2);
$this->double($class, array($interface1, $interface2))
->shouldReturnAnInstanceOf('SplStack');
}
function it_double_instantiates_a_class_with_constructor_argument(
$mirror,
\ReflectionClass $class,
ClassNode $node,
$namer
) {
$class->getName()->willReturn('ReflectionClass');
$mirror->reflect($class, array())->willReturn($node);
$namer->name($class, array())->willReturn('ReflectionClass');
$double = $this->double($class, array(), array('stdClass'));
$double->shouldBeAnInstanceOf('ReflectionClass');
$double->getName()->shouldReturn('stdClass');
}
function it_can_instantiate_class_with_final_constructor(
$mirror,
\ReflectionClass $class,
ClassNode $node,
$namer
) {
$class->getName()->willReturn('spec\Prophecy\Doubler\WithFinalConstructor');
$mirror->reflect($class, array())->willReturn($node);
$namer->name($class, array())->willReturn('spec\Prophecy\Doubler\WithFinalConstructor');
$double = $this->double($class, array());
$double->shouldBeAnInstanceOf('spec\Prophecy\Doubler\WithFinalConstructor');
}
}
class WithFinalConstructor
{
final public function __construct() {}
}

View File

@@ -0,0 +1,362 @@
<?php
namespace spec\Prophecy\Doubler\Generator;
use phpDocumentor\Reflection\DocBlock\Tags\Method;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Doubler\Generator\Node\ArgumentNode;
use Prophecy\Doubler\Generator\Node\ClassNode;
use Prophecy\Doubler\Generator\Node\MethodNode;
class ClassCodeGeneratorSpec extends ObjectBehavior
{
function it_generates_proper_php_code_for_specific_ClassNode(
ClassNode $class,
MethodNode $method1,
MethodNode $method2,
MethodNode $method3,
MethodNode $method4,
ArgumentNode $argument11,
ArgumentNode $argument12,
ArgumentNode $argument21,
ArgumentNode $argument31
) {
$class->getParentClass()->willReturn('RuntimeException');
$class->getInterfaces()->willReturn(array(
'Prophecy\Doubler\Generator\MirroredInterface', 'ArrayAccess', 'ArrayIterator'
));
$class->getProperties()->willReturn(array('name' => 'public', 'email' => 'private'));
$class->getMethods()->willReturn(array($method1, $method2, $method3, $method4));
$method1->getName()->willReturn('getName');
$method1->getVisibility()->willReturn('public');
$method1->returnsReference()->willReturn(false);
$method1->isStatic()->willReturn(true);
$method1->getArguments()->willReturn(array($argument11, $argument12));
$method1->hasReturnType()->willReturn(true);
$method1->getReturnType()->willReturn('string');
$method1->hasNullableReturnType()->willReturn(true);
$method1->getCode()->willReturn('return $this->name;');
$method2->getName()->willReturn('getEmail');
$method2->getVisibility()->willReturn('protected');
$method2->returnsReference()->willReturn(false);
$method2->isStatic()->willReturn(false);
$method2->getArguments()->willReturn(array($argument21));
$method2->hasReturnType()->willReturn(false);
$method2->hasNullableReturnType()->willReturn(true);
$method2->getCode()->willReturn('return $this->email;');
$method3->getName()->willReturn('getRefValue');
$method3->getVisibility()->willReturn('public');
$method3->returnsReference()->willReturn(true);
$method3->isStatic()->willReturn(false);
$method3->getArguments()->willReturn(array($argument31));
$method3->hasReturnType()->willReturn(true);
$method3->getReturnType()->willReturn('string');
$method3->hasNullableReturnType()->willReturn(false);
$method3->getCode()->willReturn('return $this->refValue;');
$method4->getName()->willReturn('doSomething');
$method4->getVisibility()->willReturn('public');
$method4->returnsReference()->willReturn(false);
$method4->isStatic()->willReturn(false);
$method4->getArguments()->willReturn(array());
$method4->hasReturnType()->willReturn(true);
$method4->getReturnType()->willReturn('void');
$method4->hasNullableReturnType()->willReturn(false);
$method4->getCode()->willReturn('return;');
$argument11->getName()->willReturn('fullname');
$argument11->getTypeHint()->willReturn('array');
$argument11->isOptional()->willReturn(true);
$argument11->getDefault()->willReturn(null);
$argument11->isPassedByReference()->willReturn(false);
$argument11->isVariadic()->willReturn(false);
$argument11->isNullable()->willReturn(false);
$argument12->getName()->willReturn('class');
$argument12->getTypeHint()->willReturn('ReflectionClass');
$argument12->isOptional()->willReturn(false);
$argument12->isPassedByReference()->willReturn(false);
$argument12->isVariadic()->willReturn(false);
$argument12->isNullable()->willReturn(false);
$argument21->getName()->willReturn('default');
$argument21->getTypeHint()->willReturn('string');
$argument21->isOptional()->willReturn(true);
$argument21->getDefault()->willReturn('ever.zet@gmail.com');
$argument21->isPassedByReference()->willReturn(false);
$argument21->isVariadic()->willReturn(false);
$argument21->isNullable()->willReturn(true);
$argument31->getName()->willReturn('refValue');
$argument31->getTypeHint()->willReturn(null);
$argument31->isOptional()->willReturn(false);
$argument31->getDefault()->willReturn();
$argument31->isPassedByReference()->willReturn(false);
$argument31->isVariadic()->willReturn(false);
$argument31->isNullable()->willReturn(false);
$code = $this->generate('CustomClass', $class);
if (version_compare(PHP_VERSION, '7.1', '>=')) {
$expected = <<<'PHP'
namespace {
class CustomClass extends \RuntimeException implements \Prophecy\Doubler\Generator\MirroredInterface, \ArrayAccess, \ArrayIterator {
public $name;
private $email;
public static function getName(array $fullname = NULL, \ReflectionClass $class): ?string {
return $this->name;
}
protected function getEmail(?string $default = 'ever.zet@gmail.com') {
return $this->email;
}
public function &getRefValue( $refValue): string {
return $this->refValue;
}
public function doSomething(): void {
return;
}
}
}
PHP;
} elseif (version_compare(PHP_VERSION, '7.0', '>=')) {
$expected = <<<'PHP'
namespace {
class CustomClass extends \RuntimeException implements \Prophecy\Doubler\Generator\MirroredInterface, \ArrayAccess, \ArrayIterator {
public $name;
private $email;
public static function getName(array $fullname = NULL, \ReflectionClass $class): string {
return $this->name;
}
protected function getEmail(string $default = 'ever.zet@gmail.com') {
return $this->email;
}
public function &getRefValue( $refValue): string {
return $this->refValue;
}
public function doSomething() {
return;
}
}
}
PHP;
} else {
$expected = <<<'PHP'
namespace {
class CustomClass extends \RuntimeException implements \Prophecy\Doubler\Generator\MirroredInterface, \ArrayAccess, \ArrayIterator {
public $name;
private $email;
public static function getName(array $fullname = NULL, \ReflectionClass $class) {
return $this->name;
}
protected function getEmail(\string $default = 'ever.zet@gmail.com') {
return $this->email;
}
public function &getRefValue( $refValue) {
return $this->refValue;
}
public function doSomething() {
return;
}
}
}
PHP;
}
$expected = strtr($expected, array("\r\n" => "\n", "\r" => "\n"));
$code->shouldBe($expected);
}
function it_generates_proper_php_code_for_variadics(
ClassNode $class,
MethodNode $method1,
MethodNode $method2,
MethodNode $method3,
MethodNode $method4,
ArgumentNode $argument1,
ArgumentNode $argument2,
ArgumentNode $argument3,
ArgumentNode $argument4
) {
$class->getParentClass()->willReturn('stdClass');
$class->getInterfaces()->willReturn(array('Prophecy\Doubler\Generator\MirroredInterface'));
$class->getProperties()->willReturn(array());
$class->getMethods()->willReturn(array(
$method1, $method2, $method3, $method4
));
$method1->getName()->willReturn('variadic');
$method1->getVisibility()->willReturn('public');
$method1->returnsReference()->willReturn(false);
$method1->isStatic()->willReturn(false);
$method1->getArguments()->willReturn(array($argument1));
$method1->hasReturnType()->willReturn(false);
$method1->getCode()->willReturn('');
$method2->getName()->willReturn('variadicByRef');
$method2->getVisibility()->willReturn('public');
$method2->returnsReference()->willReturn(false);
$method2->isStatic()->willReturn(false);
$method2->getArguments()->willReturn(array($argument2));
$method2->hasReturnType()->willReturn(false);
$method2->getCode()->willReturn('');
$method3->getName()->willReturn('variadicWithType');
$method3->getVisibility()->willReturn('public');
$method3->returnsReference()->willReturn(false);
$method3->isStatic()->willReturn(false);
$method3->getArguments()->willReturn(array($argument3));
$method3->hasReturnType()->willReturn(false);
$method3->getCode()->willReturn('');
$method4->getName()->willReturn('variadicWithTypeByRef');
$method4->getVisibility()->willReturn('public');
$method4->returnsReference()->willReturn(false);
$method4->isStatic()->willReturn(false);
$method4->getArguments()->willReturn(array($argument4));
$method4->hasReturnType()->willReturn(false);
$method4->getCode()->willReturn('');
$argument1->getName()->willReturn('args');
$argument1->getTypeHint()->willReturn(null);
$argument1->isOptional()->willReturn(false);
$argument1->isPassedByReference()->willReturn(false);
$argument1->isVariadic()->willReturn(true);
$argument1->isNullable()->willReturn(false);
$argument2->getName()->willReturn('args');
$argument2->getTypeHint()->willReturn(null);
$argument2->isOptional()->willReturn(false);
$argument2->isPassedByReference()->willReturn(true);
$argument2->isVariadic()->willReturn(true);
$argument2->isNullable()->willReturn(false);
$argument3->getName()->willReturn('args');
$argument3->getTypeHint()->willReturn('\ReflectionClass');
$argument3->isOptional()->willReturn(false);
$argument3->isPassedByReference()->willReturn(false);
$argument3->isVariadic()->willReturn(true);
$argument3->isNullable()->willReturn(false);
$argument4->getName()->willReturn('args');
$argument4->getTypeHint()->willReturn('\ReflectionClass');
$argument4->isOptional()->willReturn(false);
$argument4->isPassedByReference()->willReturn(true);
$argument4->isVariadic()->willReturn(true);
$argument4->isNullable()->willReturn(false);
$code = $this->generate('CustomClass', $class);
$expected = <<<'PHP'
namespace {
class CustomClass extends \stdClass implements \Prophecy\Doubler\Generator\MirroredInterface {
public function variadic( ...$args) {
}
public function variadicByRef( &...$args) {
}
public function variadicWithType(\\ReflectionClass ...$args) {
}
public function variadicWithTypeByRef(\\ReflectionClass &...$args) {
}
}
}
PHP;
$expected = strtr($expected, array("\r\n" => "\n", "\r" => "\n"));
$code->shouldBe($expected);
}
function it_overrides_properly_methods_with_args_passed_by_reference(
ClassNode $class,
MethodNode $method,
ArgumentNode $argument
) {
$class->getParentClass()->willReturn('RuntimeException');
$class->getInterfaces()->willReturn(array('Prophecy\Doubler\Generator\MirroredInterface'));
$class->getProperties()->willReturn(array());
$class->getMethods()->willReturn(array($method));
$method->getName()->willReturn('getName');
$method->getVisibility()->willReturn('public');
$method->isStatic()->willReturn(false);
$method->getArguments()->willReturn(array($argument));
$method->hasReturnType()->willReturn(false);
$method->returnsReference()->willReturn(false);
$method->getCode()->willReturn('return $this->name;');
$argument->getName()->willReturn('fullname');
$argument->getTypeHint()->willReturn('array');
$argument->isOptional()->willReturn(true);
$argument->getDefault()->willReturn(null);
$argument->isPassedByReference()->willReturn(true);
$argument->isVariadic()->willReturn(false);
$argument->isNullable()->willReturn(false);
$code = $this->generate('CustomClass', $class);
$expected =<<<'PHP'
namespace {
class CustomClass extends \RuntimeException implements \Prophecy\Doubler\Generator\MirroredInterface {
public function getName(array &$fullname = NULL) {
return $this->name;
}
}
}
PHP;
$expected = strtr($expected, array("\r\n" => "\n", "\r" => "\n"));
$code->shouldBe($expected);
}
function it_generates_empty_class_for_empty_ClassNode(ClassNode $class)
{
$class->getParentClass()->willReturn('stdClass');
$class->getInterfaces()->willReturn(array('Prophecy\Doubler\Generator\MirroredInterface'));
$class->getProperties()->willReturn(array());
$class->getMethods()->willReturn(array());
$code = $this->generate('CustomClass', $class);
$expected =<<<'PHP'
namespace {
class CustomClass extends \stdClass implements \Prophecy\Doubler\Generator\MirroredInterface {
}
}
PHP;
$expected = strtr($expected, array("\r\n" => "\n", "\r" => "\n"));
$code->shouldBe($expected);
}
function it_wraps_class_in_namespace_if_it_is_namespaced(ClassNode $class)
{
$class->getParentClass()->willReturn('stdClass');
$class->getInterfaces()->willReturn(array('Prophecy\Doubler\Generator\MirroredInterface'));
$class->getProperties()->willReturn(array());
$class->getMethods()->willReturn(array());
$code = $this->generate('My\Awesome\CustomClass', $class);
$expected =<<<'PHP'
namespace My\Awesome {
class CustomClass extends \stdClass implements \Prophecy\Doubler\Generator\MirroredInterface {
}
}
PHP;
$expected = strtr($expected, array("\r\n" => "\n", "\r" => "\n"));
$code->shouldBe($expected);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace spec\Prophecy\Doubler\Generator;
use PhpSpec\ObjectBehavior;
use Prophecy\Doubler\Generator\ClassCodeGenerator;
use Prophecy\Doubler\Generator\Node\ClassNode;
class ClassCreatorSpec extends ObjectBehavior
{
function let(ClassCodeGenerator $generator)
{
$this->beConstructedWith($generator);
}
function it_evaluates_code_generated_by_ClassCodeGenerator($generator, ClassNode $class)
{
$generator->generate('stdClass', $class)->shouldBeCalled()->willReturn(
'return 42;'
);
$this->create('stdClass', $class)->shouldReturn(42);
}
function it_throws_an_exception_if_class_does_not_exist_after_evaluation($generator, ClassNode $class)
{
$generator->generate('CustomClass', $class)->shouldBeCalled()->willReturn(
'return 42;'
);
$class->getParentClass()->willReturn('stdClass');
$class->getInterfaces()->willReturn(array('Interface1', 'Interface2'));
$this->shouldThrow('Prophecy\Exception\Doubler\ClassCreatorException')
->duringCreate('CustomClass', $class);
}
}

View File

@@ -0,0 +1,92 @@
<?php
namespace spec\Prophecy\Doubler\Generator\Node;
use PhpSpec\ObjectBehavior;
class ArgumentNodeSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('name');
}
function it_is_not_be_passed_by_reference_by_default()
{
$this->shouldNotBePassedByReference();
}
function it_is_passed_by_reference_if_marked()
{
$this->setAsPassedByReference();
$this->shouldBePassedByReference();
}
function it_is_not_variadic_by_default()
{
$this->shouldNotBeVariadic();
}
function it_is_variadic_if_marked()
{
$this->setAsVariadic();
$this->shouldBeVariadic();
}
function it_does_not_have_default_by_default()
{
$this->shouldNotHaveDefault();
}
function it_does_not_have_default_if_variadic()
{
$this->setDefault(null);
$this->setAsVariadic();
$this->shouldNotHaveDefault();
}
function it_does_have_default_if_not_variadic()
{
$this->setDefault(null);
$this->setAsVariadic(false);
$this->hasDefault()->shouldReturn(true);
}
function it_has_name_with_which_it_was_been_constructed()
{
$this->getName()->shouldReturn('name');
}
function it_has_no_typehint_by_default()
{
$this->getTypeHint()->shouldReturn(null);
}
function its_typeHint_is_mutable()
{
$this->setTypeHint('array');
$this->getTypeHint()->shouldReturn('array');
}
function it_does_not_have_default_value_by_default()
{
$this->getDefault()->shouldReturn(null);
}
function it_is_not_optional_by_default()
{
$this->isOptional()->shouldReturn(false);
}
function its_default_is_mutable()
{
$this->setDefault(array());
$this->getDefault()->shouldReturn(array());
}
function it_is_marked_as_optional_when_default_is_set()
{
$this->setDefault(null);
$this->isOptional()->shouldReturn(true);
}
}

View File

@@ -0,0 +1,185 @@
<?php
namespace spec\Prophecy\Doubler\Generator\Node;
use PhpSpec\ObjectBehavior;
use Prophecy\Doubler\Generator\Node\MethodNode;
use Prophecy\Exception\Doubler\MethodNotExtendableException;
class ClassNodeSpec extends ObjectBehavior
{
function its_parentClass_is_a_stdClass_by_default()
{
$this->getParentClass()->shouldReturn('stdClass');
}
function its_parentClass_is_mutable()
{
$this->setParentClass('Exception');
$this->getParentClass()->shouldReturn('Exception');
}
function its_parentClass_is_set_to_stdClass_if_user_set_null()
{
$this->setParentClass(null);
$this->getParentClass()->shouldReturn('stdClass');
}
function it_does_not_implement_any_interface_by_default()
{
$this->getInterfaces()->shouldHaveCount(0);
}
function its_addInterface_adds_item_to_the_list_of_implemented_interfaces()
{
$this->addInterface('MyInterface');
$this->getInterfaces()->shouldHaveCount(1);
}
function its_hasInterface_returns_true_if_class_implements_interface()
{
$this->addInterface('MyInterface');
$this->hasInterface('MyInterface')->shouldReturn(true);
}
function its_hasInterface_returns_false_if_class_does_not_implements_interface()
{
$this->hasInterface('MyInterface')->shouldReturn(false);
}
function it_supports_implementation_of_multiple_interfaces()
{
$this->addInterface('MyInterface');
$this->addInterface('MySecondInterface');
$this->getInterfaces()->shouldHaveCount(2);
}
function it_ignores_same_interfaces_added_twice()
{
$this->addInterface('MyInterface');
$this->addInterface('MyInterface');
$this->getInterfaces()->shouldHaveCount(1);
$this->getInterfaces()->shouldReturn(array('MyInterface'));
}
function it_does_not_have_methods_by_default()
{
$this->getMethods()->shouldHaveCount(0);
}
function it_can_has_methods(MethodNode $method1, MethodNode $method2)
{
$method1->getName()->willReturn('__construct');
$method2->getName()->willReturn('getName');
$this->addMethod($method1);
$this->addMethod($method2);
$this->getMethods()->shouldReturn(array(
'__construct' => $method1,
'getName' => $method2
));
}
function its_hasMethod_returns_true_if_method_exists(MethodNode $method)
{
$method->getName()->willReturn('getName');
$this->addMethod($method);
$this->hasMethod('getName')->shouldReturn(true);
}
function its_getMethod_returns_method_by_name(MethodNode $method)
{
$method->getName()->willReturn('getName');
$this->addMethod($method);
$this->getMethod('getName')->shouldReturn($method);
}
function its_hasMethod_returns_false_if_method_does_not_exists()
{
$this->hasMethod('getName')->shouldReturn(false);
}
function its_hasMethod_returns_false_if_method_has_been_removed(MethodNode $method)
{
$method->getName()->willReturn('getName');
$this->addMethod($method);
$this->removeMethod('getName');
$this->hasMethod('getName')->shouldReturn(false);
}
function it_does_not_have_properties_by_default()
{
$this->getProperties()->shouldHaveCount(0);
}
function it_is_able_to_have_properties()
{
$this->addProperty('title');
$this->addProperty('text', 'private');
$this->getProperties()->shouldReturn(array(
'title' => 'public',
'text' => 'private'
));
}
function its_addProperty_does_not_accept_unsupported_visibility()
{
$this->shouldThrow('InvalidArgumentException')->duringAddProperty('title', 'town');
}
function its_addProperty_lowercases_visibility_before_setting()
{
$this->addProperty('text', 'PRIVATE');
$this->getProperties()->shouldReturn(array('text' => 'private'));
}
function its_has_no_unextendable_methods_by_default()
{
$this->getUnextendableMethods()->shouldHaveCount(0);
}
function its_addUnextendableMethods_adds_an_unextendable_method()
{
$this->addUnextendableMethod('testMethod');
$this->getUnextendableMethods()->shouldHaveCount(1);
}
function its_methods_are_extendable_by_default()
{
$this->isExtendable('testMethod')->shouldReturn(true);
}
function its_unextendable_methods_are_not_extendable()
{
$this->addUnextendableMethod('testMethod');
$this->isExtendable('testMethod')->shouldReturn(false);
}
function its_addUnextendableMethods_doesnt_create_duplicates()
{
$this->addUnextendableMethod('testMethod');
$this->addUnextendableMethod('testMethod');
$this->getUnextendableMethods()->shouldHaveCount(1);
}
function it_throws_an_exception_when_adding_a_method_that_isnt_extendable(MethodNode $method)
{
$this->addUnextendableMethod('testMethod');
$method->getName()->willReturn('testMethod');
$expectedException = new MethodNotExtendableException(
"Method `testMethod` is not extendable, so can not be added.",
"stdClass",
"testMethod"
);
$this->shouldThrow($expectedException)->duringAddMethod($method);
}
}

View File

@@ -0,0 +1,134 @@
<?php
namespace spec\Prophecy\Doubler\Generator\Node;
use PhpSpec\ObjectBehavior;
use Prophecy\Doubler\Generator\Node\ArgumentNode;
class MethodNodeSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('getTitle');
}
function it_has_a_name()
{
$this->getName()->shouldReturn('getTitle');
}
function it_has_public_visibility_by_default()
{
$this->getVisibility()->shouldReturn('public');
}
function its_visibility_is_mutable()
{
$this->setVisibility('private');
$this->getVisibility()->shouldReturn('private');
}
function it_is_not_static_by_default()
{
$this->shouldNotBeStatic();
}
function it_does_not_return_a_reference_by_default()
{
$this->returnsReference()->shouldReturn(false);
}
function it_should_be_settable_as_returning_a_reference_through_setter()
{
$this->setReturnsReference();
$this->returnsReference()->shouldReturn(true);
}
function it_should_be_settable_as_static_through_setter()
{
$this->setStatic();
$this->shouldBeStatic();
}
function it_accepts_only_supported_visibilities()
{
$this->shouldThrow('InvalidArgumentException')->duringSetVisibility('stealth');
}
function it_lowercases_visibility_before_setting_it()
{
$this->setVisibility('Public');
$this->getVisibility()->shouldReturn('public');
}
function its_useParentCode_causes_method_to_call_parent(ArgumentNode $argument1, ArgumentNode $argument2)
{
$argument1->getName()->willReturn('objectName');
$argument2->getName()->willReturn('default');
$argument1->isVariadic()->willReturn(false);
$argument2->isVariadic()->willReturn(true);
$this->addArgument($argument1);
$this->addArgument($argument2);
$this->useParentCode();
$this->getCode()->shouldReturn(
'return parent::getTitle($objectName, ...$default);'
);
}
function its_code_is_mutable()
{
$this->setCode('echo "code";');
$this->getCode()->shouldReturn('echo "code";');
}
function its_reference_returning_methods_will_generate_exceptions()
{
$this->setCode('echo "code";');
$this->setReturnsReference();
$this->getCode()->shouldReturn("throw new \Prophecy\Exception\Doubler\ReturnByReferenceException('Returning by reference not supported', get_class(\$this), 'getTitle');");
}
function its_setCode_provided_with_null_cleans_method_body()
{
$this->setCode(null);
$this->getCode()->shouldReturn('');
}
function it_is_constructable_with_code()
{
$this->beConstructedWith('getTitle', 'die();');
$this->getCode()->shouldReturn('die();');
}
function it_does_not_have_arguments_by_default()
{
$this->getArguments()->shouldHaveCount(0);
}
function it_supports_adding_arguments(ArgumentNode $argument1, ArgumentNode $argument2)
{
$this->addArgument($argument1);
$this->addArgument($argument2);
$this->getArguments()->shouldReturn(array($argument1, $argument2));
}
function it_does_not_have_return_type_by_default()
{
$this->hasReturnType()->shouldReturn(false);
}
function it_setReturnType_sets_return_type()
{
$returnType = 'string';
$this->setReturnType($returnType);
$this->hasReturnType()->shouldReturn(true);
$this->getReturnType()->shouldReturn($returnType);
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace spec\Prophecy\Doubler;
use PhpSpec\ObjectBehavior;
use Prophecy\Doubler\Doubler;
use Prophecy\Prophecy\ProphecySubjectInterface;
class LazyDoubleSpec extends ObjectBehavior
{
function let(Doubler $doubler)
{
$this->beConstructedWith($doubler);
}
function it_returns_anonymous_double_instance_by_default($doubler, ProphecySubjectInterface $double)
{
$doubler->double(null, array())->willReturn($double);
$this->getInstance()->shouldReturn($double);
}
function it_returns_class_double_instance_if_set($doubler, ProphecySubjectInterface $double, \ReflectionClass $class)
{
$doubler->double($class, array())->willReturn($double);
$this->setParentClass($class);
$this->getInstance()->shouldReturn($double);
}
function it_returns_same_double_instance_if_called_2_times(
$doubler,
ProphecySubjectInterface $double1,
ProphecySubjectInterface $double2
) {
$doubler->double(null, array())->willReturn($double1);
$doubler->double(null, array())->willReturn($double2);
$this->getInstance()->shouldReturn($double2);
$this->getInstance()->shouldReturn($double2);
}
function its_setParentClass_throws_ClassNotFoundException_if_class_not_found()
{
$this->shouldThrow('Prophecy\Exception\Doubler\ClassNotFoundException')
->duringSetParentClass('SomeUnexistingClass');
}
function its_setParentClass_throws_exception_if_prophecy_is_already_created(
$doubler,
ProphecySubjectInterface $double
) {
$doubler->double(null, array())->willReturn($double);
$this->getInstance();
$this->shouldThrow('Prophecy\Exception\Doubler\DoubleException')
->duringSetParentClass('stdClass');
}
function its_addInterface_throws_InterfaceNotFoundException_if_no_interface_found()
{
$this->shouldThrow('Prophecy\Exception\Doubler\InterfaceNotFoundException')
->duringAddInterface('SomeUnexistingInterface');
}
function its_addInterface_throws_exception_if_prophecy_is_already_created(
$doubler,
ProphecySubjectInterface $double
) {
$doubler->double(null, array())->willReturn($double);
$this->getInstance();
$this->shouldThrow('Prophecy\Exception\Doubler\DoubleException')
->duringAddInterface('ArrayAccess');
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace spec\Prophecy\Doubler;
use PhpSpec\ObjectBehavior;
class NameGeneratorSpec extends ObjectBehavior
{
function its_name_generates_name_based_on_simple_class_reflection(\ReflectionClass $class)
{
$class->getName()->willReturn('stdClass');
$this->name($class, array())->shouldStartWith('Double\stdClass\\');
}
function its_name_generates_name_based_on_namespaced_class_reflection(\ReflectionClass $class)
{
$class->getName()->willReturn('Some\Custom\Class');
$this->name($class, array())->shouldStartWith('Double\Some\Custom\Class\P');
}
function its_name_generates_name_based_on_interface_shortnames(
\ReflectionClass $interface1,
\ReflectionClass $interface2
) {
$interface1->getShortName()->willReturn('HandlerInterface');
$interface2->getShortName()->willReturn('LoaderInterface');
$this->name(null, array($interface1, $interface2))->shouldStartWith(
'Double\HandlerInterface\LoaderInterface\P'
);
}
function it_generates_proper_name_for_no_class_and_interfaces_list()
{
$this->name(null, array())->shouldStartWith('Double\stdClass\P');
}
function its_name_generates_name_based_only_on_class_if_its_available(
\ReflectionClass $class,
\ReflectionClass $interface1,
\ReflectionClass $interface2
) {
$class->getName()->willReturn('Some\Custom\Class');
$interface1->getShortName()->willReturn('HandlerInterface');
$interface2->getShortName()->willReturn('LoaderInterface');
$this->name($class, array($interface1, $interface2))->shouldStartWith(
'Double\Some\Custom\Class\P'
);
}
public function getMatchers()
{
return array(
'startWith' => function ($subject, $string) {
return 0 === strpos($subject, $string);
},
);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace spec\Prophecy\Exception\Call;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\ObjectProphecy;
use spec\Prophecy\Exception\Prophecy\Prophecy;
class UnexpectedCallExceptionSpec extends ObjectBehavior
{
function let(ObjectProphecy $objectProphecy)
{
$this->beConstructedWith('msg', $objectProphecy, 'getName', array('arg1', 'arg2'));
}
function it_is_prophecy_exception()
{
$this->shouldBeAnInstanceOf('Prophecy\Exception\Prophecy\ObjectProphecyException');
}
function it_exposes_method_name_through_getter()
{
$this->getMethodName()->shouldReturn('getName');
}
function it_exposes_arguments_through_getter()
{
$this->getArguments()->shouldReturn(array('arg1', 'arg2'));
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace spec\Prophecy\Exception\Doubler;
use PhpSpec\ObjectBehavior;
use Prophecy\Doubler\Generator\Node\ClassNode;
use spec\Prophecy\Exception\Prophecy;
class ClassCreatorExceptionSpec extends ObjectBehavior
{
function let(ClassNode $node)
{
$this->beConstructedWith('', $node);
}
function it_is_a_prophecy_exception()
{
$this->shouldBeAnInstanceOf('Prophecy\Exception\Exception');
$this->shouldBeAnInstanceOf('Prophecy\Exception\Doubler\DoublerException');
}
function it_contains_a_reflected_node($node)
{
$this->getClassNode()->shouldReturn($node);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace spec\Prophecy\Exception\Doubler;
use PhpSpec\ObjectBehavior;
class ClassMirrorExceptionSpec extends ObjectBehavior
{
function let(\ReflectionClass $class)
{
$this->beConstructedWith('', $class);
}
function it_is_a_prophecy_exception()
{
$this->shouldBeAnInstanceOf('Prophecy\Exception\Exception');
$this->shouldBeAnInstanceOf('Prophecy\Exception\Doubler\DoublerException');
}
function it_contains_a_reflected_class_link($class)
{
$this->getReflectedClass()->shouldReturn($class);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace spec\Prophecy\Exception\Doubler;
use PhpSpec\ObjectBehavior;
use spec\Prophecy\Exception\Prophecy;
class ClassNotFoundExceptionSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('msg', 'CustomClass');
}
function it_is_a_prophecy_exception()
{
$this->shouldBeAnInstanceOf('Prophecy\Exception\Exception');
$this->shouldBeAnInstanceOf('Prophecy\Exception\Doubler\DoubleException');
}
function its_getClassname_returns_classname()
{
$this->getClassname()->shouldReturn('CustomClass');
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace spec\Prophecy\Exception\Doubler;
use PhpSpec\ObjectBehavior;
class DoubleExceptionSpec extends ObjectBehavior
{
function it_is_a_double_exception()
{
$this->shouldBeAnInstanceOf('RuntimeException');
$this->shouldBeAnInstanceOf('Prophecy\Exception\Doubler\DoublerException');
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace spec\Prophecy\Exception\Doubler;
use PhpSpec\ObjectBehavior;
use spec\Prophecy\Exception\Prophecy;
class InterfaceNotFoundExceptionSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('msg', 'CustomInterface');
}
function it_extends_ClassNotFoundException()
{
$this->shouldBeAnInstanceOf('Prophecy\Exception\Doubler\ClassNotFoundException');
}
function its_getClassname_returns_classname()
{
$this->getClassname()->shouldReturn('CustomInterface');
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace spec\Prophecy\Exception\Doubler;
use PhpSpec\ObjectBehavior;
use spec\Prophecy\Exception\Prophecy;
class MethodNotExtendableExceptionSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('', 'User', 'getName');
}
function it_is_DoubleException()
{
$this->shouldHaveType('Prophecy\Exception\Doubler\DoubleException');
}
function it_has_MethodName()
{
$this->getMethodName()->shouldReturn('getName');
}
function it_has_classname()
{
$this->getClassName()->shouldReturn('User');
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace spec\Prophecy\Exception\Doubler;
use PhpSpec\ObjectBehavior;
use spec\Prophecy\Exception\Prophecy;
class MethodNotFoundExceptionSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('', 'User', 'getName', array(1, 2, 3));
}
function it_is_DoubleException()
{
$this->shouldHaveType('Prophecy\Exception\Doubler\DoubleException');
}
function it_has_MethodName()
{
$this->getMethodName()->shouldReturn('getName');
}
function it_has_classnamej()
{
$this->getClassname()->shouldReturn('User');
}
function it_has_an_arguments_list()
{
$this->getArguments()->shouldReturn(array(1, 2, 3));
}
function it_has_a_default_null_argument_list()
{
$this->beConstructedWith('', 'User', 'getName');
$this->getArguments()->shouldReturn(null);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace spec\Prophecy\Exception\Prediction;
use PhpSpec\ObjectBehavior;
use Prophecy\Exception\Prediction\PredictionException;
use Prophecy\Prophecy\ObjectProphecy;
class AggregateExceptionSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(null);
}
function it_is_prediction_exception()
{
$this->shouldBeAnInstanceOf('RuntimeException');
$this->shouldBeAnInstanceOf('Prophecy\Exception\Prediction\PredictionException');
}
function it_can_store_objectProphecy_link(ObjectProphecy $object)
{
$this->setObjectProphecy($object);
$this->getObjectProphecy()->shouldReturn($object);
}
function it_should_not_have_exceptions_at_the_beginning()
{
$this->getExceptions()->shouldHaveCount(0);
}
function it_should_append_exception_through_append_method(PredictionException $exception)
{
$exception->getMessage()->willReturn('Exception #1');
$this->append($exception);
$this->getExceptions()->shouldReturn(array($exception));
}
function it_should_update_message_during_append(PredictionException $exception)
{
$exception->getMessage()->willReturn('Exception #1');
$this->append($exception);
$this->getMessage()->shouldReturn(" Exception #1");
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace spec\Prophecy\Exception\Prediction;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class NoCallsExceptionSpec extends ObjectBehavior
{
function let(ObjectProphecy $objectProphecy, MethodProphecy $methodProphecy)
{
$methodProphecy->getObjectProphecy()->willReturn($objectProphecy);
$this->beConstructedWith('message', $methodProphecy);
}
function it_is_PredictionException()
{
$this->shouldHaveType('Prophecy\Exception\Prediction\PredictionException');
}
function it_extends_MethodProphecyException()
{
$this->shouldHaveType('Prophecy\Exception\Prophecy\MethodProphecyException');
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace spec\Prophecy\Exception\Prediction;
use PhpSpec\ObjectBehavior;
use Prophecy\Call\Call;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class UnexpectedCallsCountExceptionSpec extends ObjectBehavior
{
function let( ObjectProphecy $objectProphecy, MethodProphecy $methodProphecy, Call $call1, Call $call2) {
$methodProphecy->getObjectProphecy()->willReturn($objectProphecy);
$this->beConstructedWith('message', $methodProphecy, 5, array($call1, $call2));
}
function it_extends_UnexpectedCallsException()
{
$this->shouldBeAnInstanceOf('Prophecy\Exception\Prediction\UnexpectedCallsException');
}
function it_should_expose_expectedCount_through_getter()
{
$this->getExpectedCount()->shouldReturn(5);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace spec\Prophecy\Exception\Prediction;
use PhpSpec\ObjectBehavior;
use Prophecy\Call\Call;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class UnexpectedCallsExceptionSpec extends ObjectBehavior
{
function let(ObjectProphecy $objectProphecy, MethodProphecy $methodProphecy, Call $call1, Call $call2)
{
$methodProphecy->getObjectProphecy()->willReturn($objectProphecy);
$this->beConstructedWith('message', $methodProphecy, array($call1, $call2));
}
function it_is_PredictionException()
{
$this->shouldHaveType('Prophecy\Exception\Prediction\PredictionException');
}
function it_extends_MethodProphecyException()
{
$this->shouldHaveType('Prophecy\Exception\Prophecy\MethodProphecyException');
}
function it_should_expose_calls_list_through_getter($call1, $call2)
{
$this->getCalls()->shouldReturn(array($call1, $call2));
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace spec\Prophecy\Exception\Prophecy;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
use spec\Prophecy\Exception\Prophecy;
class MethodProphecyExceptionSpec extends ObjectBehavior
{
function let(ObjectProphecy $objectProphecy, MethodProphecy $methodProphecy)
{
$methodProphecy->getObjectProphecy()->willReturn($objectProphecy);
$this->beConstructedWith('message', $methodProphecy);
}
function it_extends_DoubleException()
{
$this->shouldBeAnInstanceOf('Prophecy\Exception\Prophecy\ObjectProphecyException');
}
function it_holds_a_stub_reference($methodProphecy)
{
$this->getMethodProphecy()->shouldReturn($methodProphecy);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace spec\Prophecy\Exception\Prophecy;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\ObjectProphecy;
class ObjectProphecyExceptionSpec extends ObjectBehavior
{
function let(ObjectProphecy $objectProphecy)
{
$this->beConstructedWith('message', $objectProphecy);
}
function it_should_be_a_prophecy_exception()
{
$this->shouldBeAnInstanceOf('Prophecy\Exception\Prophecy\ProphecyException');
}
function it_holds_double_reference($objectProphecy)
{
$this->getObjectProphecy()->shouldReturn($objectProphecy);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace spec\Prophecy\Prediction;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Call\Call;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class CallPredictionSpec extends ObjectBehavior
{
function it_is_prediction()
{
$this->shouldHaveType('Prophecy\Prediction\PredictionInterface');
}
function it_does_nothing_if_there_is_more_than_one_call_been_made(
ObjectProphecy $object,
MethodProphecy $method,
Call $call
) {
$this->check(array($call), $object, $method)->shouldReturn(null);
}
function it_throws_NoCallsException_if_no_calls_found(
ObjectProphecy $object,
MethodProphecy $method,
ArgumentsWildcard $arguments
) {
$method->getObjectProphecy()->willReturn($object);
$method->getMethodName()->willReturn('getName');
$method->getArgumentsWildcard()->willReturn($arguments);
$arguments->__toString()->willReturn('123');
$object->reveal()->willReturn(new \stdClass());
$object->findProphecyMethodCalls('getName', Argument::any())->willReturn(array());
$this->shouldThrow('Prophecy\Exception\Prediction\NoCallsException')
->duringCheck(array(), $object, $method);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace spec\Prophecy\Prediction;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Call\Call;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class CallTimesPredictionSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(2);
}
function it_is_prediction()
{
$this->shouldHaveType('Prophecy\Prediction\PredictionInterface');
}
function it_does_nothing_if_there_were_exact_amount_of_calls_being_made(
ObjectProphecy $object,
MethodProphecy $method,
Call $call1,
Call $call2
) {
$this->check(array($call1, $call2), $object, $method)->shouldReturn(null);
}
function it_throws_UnexpectedCallsCountException_if_calls_found(
ObjectProphecy $object,
MethodProphecy $method,
Call $call,
ArgumentsWildcard $arguments
) {
$method->getObjectProphecy()->willReturn($object);
$method->getMethodName()->willReturn('getName');
$method->getArgumentsWildcard()->willReturn($arguments);
$arguments->__toString()->willReturn('123');
$call->getMethodName()->willReturn('getName');
$call->getArguments()->willReturn(array(5, 4, 'three'));
$call->getCallPlace()->willReturn('unknown');
$this->shouldThrow('Prophecy\Exception\Prediction\UnexpectedCallsCountException')
->duringCheck(array($call), $object, $method);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace spec\Prophecy\Prediction;
use PhpSpec\ObjectBehavior;
use Prophecy\Call\Call;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
use RuntimeException;
class CallbackPredictionSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('get_class');
}
function it_is_prediction()
{
$this->shouldHaveType('Prophecy\Prediction\PredictionInterface');
}
function it_proxies_call_to_callback(ObjectProphecy $object, MethodProphecy $method, Call $call)
{
$returnFirstCallCallback = function ($calls, $object, $method) {
throw new RuntimeException;
};
$this->beConstructedWith($returnFirstCallCallback);
$this->shouldThrow('RuntimeException')->duringCheck(array($call), $object, $method);
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace spec\Prophecy\Prediction;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Call\Call;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class NoCallsPredictionSpec extends ObjectBehavior
{
function it_is_prediction()
{
$this->shouldHaveType('Prophecy\Prediction\PredictionInterface');
}
function it_does_nothing_if_there_is_no_calls_made(ObjectProphecy $object, MethodProphecy $method)
{
$this->check(array(), $object, $method)->shouldReturn(null);
}
function it_throws_UnexpectedCallsException_if_calls_found(
ObjectProphecy $object,
MethodProphecy $method,
Call $call,
ArgumentsWildcard $arguments
) {
$method->getObjectProphecy()->willReturn($object);
$method->getMethodName()->willReturn('getName');
$method->getArgumentsWildcard()->willReturn($arguments);
$arguments->__toString()->willReturn('123');
$call->getMethodName()->willReturn('getName');
$call->getArguments()->willReturn(array(5, 4, 'three'));
$call->getCallPlace()->willReturn('unknown');
$this->shouldThrow('Prophecy\Exception\Prediction\UnexpectedCallsException')
->duringCheck(array($call), $object, $method);
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace spec\Prophecy\Promise;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class CallbackPromiseSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('get_class');
}
function it_is_promise()
{
$this->shouldBeAnInstanceOf('Prophecy\Promise\PromiseInterface');
}
function it_should_execute_closure_callback(ObjectProphecy $object, MethodProphecy $method)
{
$firstArgumentCallback = function ($args) {
return $args[0];
};
$this->beConstructedWith($firstArgumentCallback);
$this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');
}
function it_should_execute_static_array_callback(ObjectProphecy $object, MethodProphecy $method)
{
$firstArgumentCallback = array('spec\Prophecy\Promise\ClassCallback', 'staticCallbackMethod');
$this->beConstructedWith($firstArgumentCallback);
$this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');
}
function it_should_execute_instance_array_callback(ObjectProphecy $object, MethodProphecy $method)
{
$class = new ClassCallback();
$firstArgumentCallback = array($class, 'callbackMethod');
$this->beConstructedWith($firstArgumentCallback);
$this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');
}
function it_should_execute_string_function_callback(ObjectProphecy $object, MethodProphecy $method)
{
$firstArgumentCallback = 'spec\Prophecy\Promise\functionCallbackFirstArgument';
$this->beConstructedWith($firstArgumentCallback);
$this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');
}
}
/**
* Class used to test callbackpromise
*
* @param array
* @return string
*/
class ClassCallback
{
/**
* @param array $args
*/
function callbackMethod($args)
{
return $args[0];
}
/**
* @param array $args
*/
static function staticCallbackMethod($args)
{
return $args[0];
}
}
/**
* Callback function used to test callbackpromise
*
* @param array
* @return string
*/
function functionCallbackFirstArgument($args)
{
return $args[0];
}

View File

@@ -0,0 +1,31 @@
<?php
namespace spec\Prophecy\Promise;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class ReturnArgumentPromiseSpec extends ObjectBehavior
{
function it_is_promise()
{
$this->shouldBeAnInstanceOf('Prophecy\Promise\PromiseInterface');
}
function it_should_return_first_argument_if_provided(ObjectProphecy $object, MethodProphecy $method)
{
$this->execute(array('one', 'two'), $object, $method)->shouldReturn('one');
}
function it_should_return_null_if_no_arguments_provided(ObjectProphecy $object, MethodProphecy $method)
{
$this->execute(array(), $object, $method)->shouldReturn(null);
}
function it_should_return_nth_argument_if_provided(ObjectProphecy $object, MethodProphecy $method)
{
$this->beConstructedWith(1);
$this->execute(array('one', 'two'), $object, $method)->shouldReturn('two');
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace spec\Prophecy\Promise;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class ReturnPromiseSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(array(42));
}
function it_is_promise()
{
$this->shouldBeAnInstanceOf('Prophecy\Promise\PromiseInterface');
}
function it_returns_value_it_was_constructed_with(ObjectProphecy $object, MethodProphecy $method)
{
$this->execute(array(), $object, $method)->shouldReturn(42);
}
function it_always_returns_last_value_left_in_the_return_values(ObjectProphecy $object, MethodProphecy $method)
{
$this->execute(array(), $object, $method)->shouldReturn(42);
$this->execute(array(), $object, $method)->shouldReturn(42);
}
function it_consequently_returns_multiple_values_it_was_constructed_with(
ObjectProphecy $object,
MethodProphecy $method
) {
$this->beConstructedWith(array(42, 24, 12));
$this->execute(array(), $object, $method)->shouldReturn(42);
$this->execute(array(), $object, $method)->shouldReturn(24);
$this->execute(array(), $object, $method)->shouldReturn(12);
}
function it_returns_null_if_constructed_with_empty_array(ObjectProphecy $object, MethodProphecy $method)
{
$this->beConstructedWith(array());
$this->execute(array(), $object, $method)->shouldReturn(null);
}
}

View File

@@ -0,0 +1,92 @@
<?php
namespace spec\Prophecy\Promise;
use PhpSpec\Exception\Example\SkippingException;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ObjectProphecy;
class ThrowPromiseSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith('RuntimeException');
}
function it_is_promise()
{
$this->shouldBeAnInstanceOf('Prophecy\Promise\PromiseInterface');
}
function it_instantiates_and_throws_exception_from_provided_classname(ObjectProphecy $object, MethodProphecy $method)
{
$this->beConstructedWith('InvalidArgumentException');
$this->shouldThrow('InvalidArgumentException')
->duringExecute(array(), $object, $method);
}
function it_instantiates_exceptions_with_required_arguments(ObjectProphecy $object, MethodProphecy $method)
{
$this->beConstructedWith('spec\Prophecy\Promise\RequiredArgumentException');
$this->shouldThrow('spec\Prophecy\Promise\RequiredArgumentException')
->duringExecute(array(), $object, $method);
}
function it_throws_provided_exception(ObjectProphecy $object, MethodProphecy $method)
{
$this->beConstructedWith($exc = new \RuntimeException('Some exception'));
$this->shouldThrow($exc)->duringExecute(array(), $object, $method);
}
function it_throws_error_instances(ObjectProphecy $object, MethodProphecy $method)
{
if (!class_exists('\Error')) {
throw new SkippingException('The class Error, introduced in PHP 7, does not exist');
}
$this->beConstructedWith($exc = new \Error('Error exception'));
$this->shouldThrow($exc)->duringExecute(array(), $object, $method);
}
function it_throws_errors_by_class_name()
{
if (!class_exists('\Error')) {
throw new SkippingException('The class Error, introduced in PHP 7, does not exist');
}
$this->beConstructedWith('\Error');
$this->shouldNotThrow('Prophecy\Exception\InvalidArgumentException')->duringInstantiation();
}
function it_does_not_throw_something_that_is_not_throwable_by_class_name()
{
$this->beConstructedWith('\stdClass');
$this->shouldThrow('Prophecy\Exception\InvalidArgumentException')->duringInstantiation();
}
function it_does_not_throw_something_that_is_not_throwable_by_instance()
{
$this->beConstructedWith(new \stdClass());
$this->shouldThrow('Prophecy\Exception\InvalidArgumentException')->duringInstantiation();
}
function it_throws_an_exception_by_class_name()
{
$this->beConstructedWith('\Exception');
$this->shouldNotThrow('Prophecy\Exception\InvalidArgumentException')->duringInstantiation();
}
}
class RequiredArgumentException extends \Exception
{
final public function __construct($message, $code) {}
}

View File

@@ -0,0 +1,342 @@
<?php
namespace spec\Prophecy\Prophecy;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Call\Call;
use Prophecy\Prediction\PredictionInterface;
use Prophecy\Promise\PromiseInterface;
use Prophecy\Prophecy\ObjectProphecy;
class ClassWithFinalMethod
{
final public function finalMethod() {}
}
class MethodProphecySpec extends ObjectBehavior
{
function let(ObjectProphecy $objectProphecy, \ReflectionClass $reflection)
{
$objectProphecy->reveal()->willReturn($reflection);
$this->beConstructedWith($objectProphecy, 'getName', null);
}
function it_is_initializable()
{
$this->shouldHaveType('Prophecy\Prophecy\MethodProphecy');
}
function its_constructor_throws_MethodNotFoundException_for_unexisting_method($objectProphecy)
{
$this->shouldThrow('Prophecy\Exception\Doubler\MethodNotFoundException')->during(
'__construct', array($objectProphecy, 'getUnexisting', null)
);
}
function its_constructor_throws_MethodProphecyException_for_final_methods($objectProphecy, ClassWithFinalMethod $subject)
{
$objectProphecy->reveal()->willReturn($subject);
$this->shouldThrow('Prophecy\Exception\Prophecy\MethodProphecyException')->during(
'__construct', array($objectProphecy, 'finalMethod', null)
);
}
function its_constructor_transforms_array_passed_as_3rd_argument_to_ArgumentsWildcard(
$objectProphecy
)
{
$this->beConstructedWith($objectProphecy, 'getName', array(42, 33));
$wildcard = $this->getArgumentsWildcard();
$wildcard->shouldNotBe(null);
$wildcard->__toString()->shouldReturn('exact(42), exact(33)');
}
function its_constructor_does_not_touch_third_argument_if_it_is_null($objectProphecy)
{
$this->beConstructedWith($objectProphecy, 'getName', null);
$wildcard = $this->getArgumentsWildcard();
$wildcard->shouldBe(null);
}
function it_records_promise_through_will_method(PromiseInterface $promise, $objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->will($promise);
$this->getPromise()->shouldReturn($promise);
}
function it_adds_itself_to_ObjectProphecy_during_call_to_will(PromiseInterface $objectProphecy, $promise)
{
$objectProphecy->addMethodProphecy($this)->shouldBeCalled();
$this->will($promise);
}
function it_adds_ReturnPromise_during_willReturn_call($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->willReturn(42);
$this->getPromise()->shouldBeAnInstanceOf('Prophecy\Promise\ReturnPromise');
}
function it_adds_ThrowPromise_during_willThrow_call($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->willThrow('RuntimeException');
$this->getPromise()->shouldBeAnInstanceOf('Prophecy\Promise\ThrowPromise');
}
function it_adds_ReturnArgumentPromise_during_willReturnArgument_call($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->willReturnArgument();
$this->getPromise()->shouldBeAnInstanceOf('Prophecy\Promise\ReturnArgumentPromise');
}
function it_adds_ReturnArgumentPromise_during_willReturnArgument_call_with_index_argument($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->willReturnArgument(1);
$promise = $this->getPromise();
$promise->shouldBeAnInstanceOf('Prophecy\Promise\ReturnArgumentPromise');
$promise->execute(array('one', 'two'), $objectProphecy, $this)->shouldReturn('two');
}
function it_adds_CallbackPromise_during_will_call_with_callback_argument($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$callback = function () {};
$this->will($callback);
$this->getPromise()->shouldBeAnInstanceOf('Prophecy\Promise\CallbackPromise');
}
function it_records_prediction_through_should_method(PredictionInterface $prediction, $objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->callOnWrappedObject('should', array($prediction));
$this->getPrediction()->shouldReturn($prediction);
}
function it_adds_CallbackPrediction_during_should_call_with_callback_argument($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$callback = function () {};
$this->callOnWrappedObject('should', array($callback));
$this->getPrediction()->shouldBeAnInstanceOf('Prophecy\Prediction\CallbackPrediction');
}
function it_adds_itself_to_ObjectProphecy_during_call_to_should($objectProphecy, PredictionInterface $prediction)
{
$objectProphecy->addMethodProphecy($this)->shouldBeCalled();
$this->callOnWrappedObject('should', array($prediction));
}
function it_adds_CallPrediction_during_shouldBeCalled_call($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->callOnWrappedObject('shouldBeCalled', array());
$this->getPrediction()->shouldBeAnInstanceOf('Prophecy\Prediction\CallPrediction');
}
function it_adds_NoCallsPrediction_during_shouldNotBeCalled_call($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->callOnWrappedObject('shouldNotBeCalled', array());
$this->getPrediction()->shouldBeAnInstanceOf('Prophecy\Prediction\NoCallsPrediction');
}
function it_adds_CallTimesPrediction_during_shouldBeCalledTimes_call($objectProphecy)
{
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->callOnWrappedObject('shouldBeCalledTimes', array(5));
$this->getPrediction()->shouldBeAnInstanceOf('Prophecy\Prediction\CallTimesPrediction');
}
function it_checks_prediction_via_shouldHave_method_call(
$objectProphecy,
ArgumentsWildcard $arguments,
PredictionInterface $prediction,
Call $call1,
Call $call2
) {
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->shouldBeCalled();
$objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));
$this->withArguments($arguments);
$this->callOnWrappedObject('shouldHave', array($prediction));
}
function it_sets_return_promise_during_shouldHave_call_if_none_was_set_before(
$objectProphecy,
ArgumentsWildcard $arguments,
PredictionInterface $prediction,
Call $call1,
Call $call2
) {
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->shouldBeCalled();
$objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));
$this->withArguments($arguments);
$this->callOnWrappedObject('shouldHave', array($prediction));
$this->getPromise()->shouldReturnAnInstanceOf('Prophecy\Promise\ReturnPromise');
}
function it_does_not_set_return_promise_during_shouldHave_call_if_it_was_set_before(
$objectProphecy,
ArgumentsWildcard $arguments,
PredictionInterface $prediction,
Call $call1,
Call $call2,
PromiseInterface $promise
) {
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->shouldBeCalled();
$objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));
$this->will($promise);
$this->withArguments($arguments);
$this->callOnWrappedObject('shouldHave', array($prediction));
$this->getPromise()->shouldReturn($promise);
}
function it_records_checked_predictions(
$objectProphecy,
ArgumentsWildcard $arguments,
PredictionInterface $prediction1,
PredictionInterface $prediction2,
Call $call1,
Call $call2,
PromiseInterface $promise
) {
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$prediction1->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->willReturn();
$prediction2->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->willReturn();
$objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));
$this->will($promise);
$this->withArguments($arguments);
$this->callOnWrappedObject('shouldHave', array($prediction1));
$this->callOnWrappedObject('shouldHave', array($prediction2));
$this->getCheckedPredictions()->shouldReturn(array($prediction1, $prediction2));
}
function it_records_even_failed_checked_predictions(
$objectProphecy,
ArgumentsWildcard $arguments,
PredictionInterface $prediction,
Call $call1,
Call $call2,
PromiseInterface $promise
) {
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->willThrow(new \RuntimeException());
$objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));
$this->will($promise);
$this->withArguments($arguments);
try {
$this->callOnWrappedObject('shouldHave', array($prediction));
} catch (\Exception $e) {}
$this->getCheckedPredictions()->shouldReturn(array($prediction));
}
function it_checks_prediction_via_shouldHave_method_call_with_callback(
$objectProphecy,
ArgumentsWildcard $arguments,
Call $call1,
Call $call2
) {
$callback = function ($calls, $object, $method) {
throw new \RuntimeException;
};
$objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));
$this->withArguments($arguments);
$this->shouldThrow('RuntimeException')->duringShouldHave($callback);
}
function it_does_nothing_during_checkPrediction_if_no_prediction_set()
{
$this->checkPrediction()->shouldReturn(null);
}
function it_checks_set_prediction_during_checkPrediction(
$objectProphecy,
ArgumentsWildcard $arguments,
PredictionInterface $prediction,
Call $call1,
Call $call2
) {
$prediction->check(array($call1, $call2), $objectProphecy->getWrappedObject(), $this)->shouldBeCalled();
$objectProphecy->findProphecyMethodCalls('getName', $arguments)->willReturn(array($call1, $call2));
$objectProphecy->addMethodProphecy($this)->willReturn(null);
$this->withArguments($arguments);
$this->callOnWrappedObject('should', array($prediction));
$this->checkPrediction();
}
function it_links_back_to_ObjectProphecy_through_getter($objectProphecy)
{
$this->getObjectProphecy()->shouldReturn($objectProphecy);
}
function it_has_MethodName()
{
$this->getMethodName()->shouldReturn('getName');
}
function it_contains_ArgumentsWildcard_it_was_constructed_with($objectProphecy, ArgumentsWildcard $wildcard)
{
$this->beConstructedWith($objectProphecy, 'getName', $wildcard);
$this->getArgumentsWildcard()->shouldReturn($wildcard);
}
function its_ArgumentWildcard_is_mutable_through_setter(ArgumentsWildcard $wildcard)
{
$this->withArguments($wildcard);
$this->getArgumentsWildcard()->shouldReturn($wildcard);
}
function its_withArguments_transforms_passed_array_into_ArgumentsWildcard()
{
$this->withArguments(array(42, 33));
$wildcard = $this->getArgumentsWildcard();
$wildcard->shouldNotBe(null);
$wildcard->__toString()->shouldReturn('exact(42), exact(33)');
}
function its_withArguments_throws_exception_if_wrong_arguments_provided()
{
$this->shouldThrow('Prophecy\Exception\InvalidArgumentException')->duringWithArguments(42);
}
}

View File

@@ -0,0 +1,283 @@
<?php
namespace spec\Prophecy\Prophecy;
use phpDocumentor\Reflection\DocBlock\Tags\Method;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Call\Call;
use Prophecy\Call\CallCenter;
use Prophecy\Doubler\Doubler;
use Prophecy\Doubler\LazyDouble;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ProphecySubjectInterface;
use Prophecy\Prophecy\RevealerInterface;
class ObjectProphecySpec extends ObjectBehavior
{
function let(LazyDouble $lazyDouble, ProphecySubjectInterface $double)
{
$this->beConstructedWith($lazyDouble);
$lazyDouble->getInstance()->willReturn($double);
}
function it_implements_ProphecyInterface()
{
$this->shouldBeAnInstanceOf('Prophecy\Prophecy\ProphecyInterface');
}
function it_sets_parentClass_during_willExtend_call($lazyDouble)
{
$lazyDouble->setParentClass('123')->shouldBeCalled();
$this->willExtend('123');
}
function it_adds_interface_during_willImplement_call($lazyDouble)
{
$lazyDouble->addInterface('222')->shouldBeCalled();
$this->willImplement('222');
}
function it_sets_constructor_arguments_during_willBeConstructedWith_call($lazyDouble)
{
$lazyDouble->setArguments(array(1, 2, 5))->shouldBeCalled();
$this->willBeConstructedWith(array(1, 2, 5));
}
function it_does_not_have_method_prophecies_by_default()
{
$this->getMethodProphecies()->shouldHaveCount(0);
}
function it_should_get_method_prophecies_by_method_name(
MethodProphecy $method1,
MethodProphecy $method2,
ArgumentsWildcard $arguments
) {
$method1->getMethodName()->willReturn('getName');
$method1->getArgumentsWildcard()->willReturn($arguments);
$method2->getMethodName()->willReturn('setName');
$method2->getArgumentsWildcard()->willReturn($arguments);
$this->addMethodProphecy($method1);
$this->addMethodProphecy($method2);
$methods = $this->getMethodProphecies('setName');
$methods->shouldHaveCount(1);
$methods[0]->getMethodName()->shouldReturn('setName');
}
function it_should_return_empty_array_if_no_method_prophecies_found()
{
$methods = $this->getMethodProphecies('setName');
$methods->shouldHaveCount(0);
}
function it_should_proxy_makeProphecyMethodCall_to_CallCenter($lazyDouble, CallCenter $callCenter)
{
$this->beConstructedWith($lazyDouble, $callCenter);
$callCenter->makeCall($this->getWrappedObject(), 'setName', array('everzet'))->willReturn(42);
$this->makeProphecyMethodCall('setName', array('everzet'))->shouldReturn(42);
}
function it_should_reveal_arguments_and_return_values_from_callCenter(
$lazyDouble,
CallCenter $callCenter,
RevealerInterface $revealer
) {
$this->beConstructedWith($lazyDouble, $callCenter, $revealer);
$revealer->reveal(array('question'))->willReturn(array('life'));
$revealer->reveal('answer')->willReturn(42);
$callCenter->makeCall($this->getWrappedObject(), 'setName', array('life'))->willReturn('answer');
$this->makeProphecyMethodCall('setName', array('question'))->shouldReturn(42);
}
function it_should_proxy_getProphecyMethodCalls_to_CallCenter(
$lazyDouble,
CallCenter $callCenter,
ArgumentsWildcard $wildcard,
Call $call
) {
$this->beConstructedWith($lazyDouble, $callCenter);
$callCenter->findCalls('setName', $wildcard)->willReturn(array($call));
$this->findProphecyMethodCalls('setName', $wildcard)->shouldReturn(array($call));
}
function its_addMethodProphecy_adds_method_prophecy(
MethodProphecy $methodProphecy,
ArgumentsWildcard $argumentsWildcard
) {
$methodProphecy->getArgumentsWildcard()->willReturn($argumentsWildcard);
$methodProphecy->getMethodName()->willReturn('getUsername');
$this->addMethodProphecy($methodProphecy);
$this->getMethodProphecies()->shouldReturn(array(
'getUsername' => array($methodProphecy)
));
}
function its_addMethodProphecy_handles_prophecies_with_different_arguments(
MethodProphecy $methodProphecy1,
MethodProphecy $methodProphecy2,
ArgumentsWildcard $argumentsWildcard1,
ArgumentsWildcard $argumentsWildcard2
) {
$methodProphecy1->getArgumentsWildcard()->willReturn($argumentsWildcard1);
$methodProphecy1->getMethodName()->willReturn('getUsername');
$methodProphecy2->getArgumentsWildcard()->willReturn($argumentsWildcard2);
$methodProphecy2->getMethodName()->willReturn('getUsername');
$this->addMethodProphecy($methodProphecy1);
$this->addMethodProphecy($methodProphecy2);
$this->getMethodProphecies()->shouldReturn(array(
'getUsername' => array(
$methodProphecy1,
$methodProphecy2,
)
));
}
function its_addMethodProphecy_handles_prophecies_for_different_methods(
MethodProphecy $methodProphecy1,
MethodProphecy $methodProphecy2,
ArgumentsWildcard $argumentsWildcard1,
ArgumentsWildcard $argumentsWildcard2
) {
$methodProphecy1->getArgumentsWildcard()->willReturn($argumentsWildcard1);
$methodProphecy1->getMethodName()->willReturn('getUsername');
$methodProphecy2->getArgumentsWildcard()->willReturn($argumentsWildcard2);
$methodProphecy2->getMethodName()->willReturn('isUsername');
$this->addMethodProphecy($methodProphecy1);
$this->addMethodProphecy($methodProphecy2);
$this->getMethodProphecies()->shouldReturn(array(
'getUsername' => array(
$methodProphecy1
),
'isUsername' => array(
$methodProphecy2
)
));
}
function its_addMethodProphecy_throws_exception_when_method_has_no_ArgumentsWildcard(MethodProphecy $methodProphecy)
{
$methodProphecy->getArgumentsWildcard()->willReturn(null);
$methodProphecy->getObjectProphecy()->willReturn($this);
$methodProphecy->getMethodName()->willReturn('getTitle');
$this->shouldThrow('Prophecy\Exception\Prophecy\MethodProphecyException')->duringAddMethodProphecy(
$methodProphecy
);
}
function it_returns_null_after_checkPredictions_call_if_there_is_no_method_prophecies()
{
$this->checkProphecyMethodsPredictions()->shouldReturn(null);
}
function it_throws_AggregateException_during_checkPredictions_if_predictions_fail(
MethodProphecy $methodProphecy1, MethodProphecy $methodProphecy2,
ArgumentsWildcard $argumentsWildcard1,
ArgumentsWildcard $argumentsWildcard2
) {
$methodProphecy1->getMethodName()->willReturn('getName');
$methodProphecy1->getArgumentsWildcard()->willReturn($argumentsWildcard1);
$methodProphecy1->checkPrediction()
->willThrow('Prophecy\Exception\Prediction\AggregateException');
$methodProphecy2->getMethodName()->willReturn('setName');
$methodProphecy2->getArgumentsWildcard()->willReturn($argumentsWildcard2);
$methodProphecy2->checkPrediction()
->willThrow('Prophecy\Exception\Prediction\AggregateException');
$this->addMethodProphecy($methodProphecy1);
$this->addMethodProphecy($methodProphecy2);
$this->shouldThrow('Prophecy\Exception\Prediction\AggregateException')
->duringCheckProphecyMethodsPredictions();
}
function it_returns_new_MethodProphecy_instance_for_arbitrary_call(
Doubler $doubler,
ProphecySubjectInterface $reflection
) {
$doubler->double(Argument::any())->willReturn($reflection);
$return = $this->getProphecy();
$return->shouldBeAnInstanceOf('Prophecy\Prophecy\MethodProphecy');
$return->getMethodName()->shouldReturn('getProphecy');
}
function it_returns_same_MethodProphecy_for_same_registered_signature(
Doubler $doubler,
ProphecySubjectInterface $reflection
) {
$doubler->double(Argument::any())->willReturn($reflection);
$this->addMethodProphecy($methodProphecy1 = $this->getProphecy(1, 2, 3));
$methodProphecy2 = $this->getProphecy(1, 2, 3);
$methodProphecy2->shouldBe($methodProphecy1);
}
function it_returns_new_MethodProphecy_for_different_signatures(
Doubler $doubler,
ProphecySubjectInterface $reflection
) {
$doubler->double(Argument::any())->willReturn($reflection);
$value = new ObjectProphecySpecFixtureB('ABC');
$value2 = new ObjectProphecySpecFixtureB('CBA');
$this->addMethodProphecy($methodProphecy1 = $this->getProphecy(1, 2, 3, $value));
$methodProphecy2 = $this->getProphecy(1, 2, 3, $value2);
$methodProphecy2->shouldNotBe($methodProphecy1);
}
function it_returns_new_MethodProphecy_for_all_callback_signatures(
Doubler $doubler,
ProphecySubjectInterface $reflection
) {
$doubler->double(Argument::any())->willReturn($reflection);
$this->addMethodProphecy($methodProphecy1 = $this->getProphecy(function(){}));
$methodProphecy2 = $this->getProphecy(function(){});
$methodProphecy2->shouldNotBe($methodProphecy1);
}
}
class ObjectProphecySpecFixtureA
{
public $errors;
}
class ObjectProphecySpecFixtureB extends ObjectProphecySpecFixtureA
{
public $errors;
public $value = null;
public function __construct($value)
{
$this->value = $value;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace spec\Prophecy\Prophecy;
use PhpSpec\ObjectBehavior;
use Prophecy\Prophecy\ProphecyInterface;
class RevealerSpec extends ObjectBehavior
{
function it_is_revealer()
{
$this->shouldBeAnInstanceOf('Prophecy\Prophecy\RevealerInterface');
}
function it_reveals_single_instance_of_ProphecyInterface(ProphecyInterface $prophecy, \stdClass $object)
{
$prophecy->reveal()->willReturn($object);
$this->reveal($prophecy)->shouldReturn($object);
}
function it_reveals_instances_of_ProphecyInterface_inside_array(
ProphecyInterface $prophecy1,
ProphecyInterface $prophecy2,
\stdClass $object1,
\stdClass $object2
) {
$prophecy1->reveal()->willReturn($object1);
$prophecy2->reveal()->willReturn($object2);
$this->reveal(array(
array('item' => $prophecy2),
$prophecy1
))->shouldReturn(array(
array('item' => $object2),
$object1
));
}
function it_does_not_touch_non_prophecy_interface()
{
$this->reveal(42)->shouldReturn(42);
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace spec\Prophecy;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Argument\ArgumentsWildcard;
use Prophecy\Doubler\Doubler;
use Prophecy\Prophecy\MethodProphecy;
use Prophecy\Prophecy\ProphecySubjectInterface;
class ProphetSpec extends ObjectBehavior
{
function let(Doubler $doubler, ProphecySubjectInterface $double)
{
$doubler->double(null, array())->willReturn($double);
$this->beConstructedWith($doubler);
}
function it_constructs_new_prophecy_on_prophesize_call()
{
$prophecy = $this->prophesize();
$prophecy->shouldBeAnInstanceOf('Prophecy\Prophecy\ObjectProphecy');
}
function it_constructs_new_prophecy_with_parent_class_if_specified($doubler, ProphecySubjectInterface $newDouble)
{
$doubler->double(Argument::any(), array())->willReturn($newDouble);
$this->prophesize('Prophecy\Prophet')->reveal()->shouldReturn($newDouble);
}
function it_constructs_new_prophecy_with_interface_if_specified($doubler, ProphecySubjectInterface $newDouble)
{
$doubler->double(null, Argument::any())->willReturn($newDouble);
$this->prophesize('ArrayAccess')->reveal()->shouldReturn($newDouble);
}
function it_exposes_all_created_prophecies_through_getter()
{
$prophecy1 = $this->prophesize();
$prophecy2 = $this->prophesize();
$this->getProphecies()->shouldReturn(array($prophecy1, $prophecy2));
}
function it_does_nothing_during_checkPredictions_call_if_no_predictions_defined()
{
$this->checkPredictions()->shouldReturn(null);
}
function it_throws_AggregateException_if_defined_predictions_fail(
MethodProphecy $method1,
MethodProphecy $method2,
ArgumentsWildcard $arguments1,
ArgumentsWildcard $arguments2
) {
$method1->getMethodName()->willReturn('getName');
$method1->getArgumentsWildcard()->willReturn($arguments1);
$method1->checkPrediction()->willReturn(null);
$method2->getMethodName()->willReturn('isSet');
$method2->getArgumentsWildcard()->willReturn($arguments2);
$method2->checkPrediction()->willThrow(
'Prophecy\Exception\Prediction\AggregateException'
);
$this->prophesize()->addMethodProphecy($method1);
$this->prophesize()->addMethodProphecy($method2);
$this->shouldThrow('Prophecy\Exception\Prediction\AggregateException')
->duringCheckPredictions();
}
function it_exposes_doubler_through_getter($doubler)
{
$this->getDoubler()->shouldReturn($doubler);
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace spec\Prophecy\Util;
use PhpSpec\ObjectBehavior;
class StringUtilSpec extends ObjectBehavior
{
function it_generates_proper_string_representation_for_integer()
{
$this->stringify(42)->shouldReturn('42');
}
function it_generates_proper_string_representation_for_string()
{
$this->stringify('some string')->shouldReturn('"some string"');
}
function it_generates_single_line_representation_for_multiline_string()
{
$this->stringify("some\nstring")->shouldReturn('"some\\nstring"');
}
function it_generates_proper_string_representation_for_double()
{
$this->stringify(42.3)->shouldReturn('42.3');
}
function it_generates_proper_string_representation_for_boolean_true()
{
$this->stringify(true)->shouldReturn('true');
}
function it_generates_proper_string_representation_for_boolean_false()
{
$this->stringify(false)->shouldReturn('false');
}
function it_generates_proper_string_representation_for_null()
{
$this->stringify(null)->shouldReturn('null');
}
function it_generates_proper_string_representation_for_empty_array()
{
$this->stringify(array())->shouldReturn('[]');
}
function it_generates_proper_string_representation_for_array()
{
$this->stringify(array('zet', 42))->shouldReturn('["zet", 42]');
}
function it_generates_proper_string_representation_for_hash_containing_one_value()
{
$this->stringify(array('ever' => 'zet'))->shouldReturn('["ever" => "zet"]');
}
function it_generates_proper_string_representation_for_hash()
{
$this->stringify(array('ever' => 'zet', 52 => 'hey', 'num' => 42))->shouldReturn(
'["ever" => "zet", 52 => "hey", "num" => 42]'
);
}
function it_generates_proper_string_representation_for_resource()
{
$resource = fopen(__FILE__, 'r');
$this->stringify($resource)->shouldReturn('stream:'.$resource);
}
function it_generates_proper_string_representation_for_object(\stdClass $object)
{
$objHash = sprintf('%s:%s',
get_class($object->getWrappedObject()),
spl_object_hash($object->getWrappedObject())
) . " Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n)";
$this->stringify($object)->shouldReturn("$objHash");
}
function it_generates_proper_string_representation_for_object_without_exporting(\stdClass $object)
{
$objHash = sprintf('%s:%s',
get_class($object->getWrappedObject()),
spl_object_hash($object->getWrappedObject())
);
$this->stringify($object, false)->shouldReturn("$objHash");
}
}

View File

@@ -0,0 +1,212 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy;
use Prophecy\Argument\Token;
/**
* Argument tokens shortcuts.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Argument
{
/**
* Checks that argument is exact value or object.
*
* @param mixed $value
*
* @return Token\ExactValueToken
*/
public static function exact($value)
{
return new Token\ExactValueToken($value);
}
/**
* Checks that argument is of specific type or instance of specific class.
*
* @param string $type Type name (`integer`, `string`) or full class name
*
* @return Token\TypeToken
*/
public static function type($type)
{
return new Token\TypeToken($type);
}
/**
* Checks that argument object has specific state.
*
* @param string $methodName
* @param mixed $value
*
* @return Token\ObjectStateToken
*/
public static function which($methodName, $value)
{
return new Token\ObjectStateToken($methodName, $value);
}
/**
* Checks that argument matches provided callback.
*
* @param callable $callback
*
* @return Token\CallbackToken
*/
public static function that($callback)
{
return new Token\CallbackToken($callback);
}
/**
* Matches any single value.
*
* @return Token\AnyValueToken
*/
public static function any()
{
return new Token\AnyValueToken;
}
/**
* Matches all values to the rest of the signature.
*
* @return Token\AnyValuesToken
*/
public static function cetera()
{
return new Token\AnyValuesToken;
}
/**
* Checks that argument matches all tokens
*
* @param mixed ... a list of tokens
*
* @return Token\LogicalAndToken
*/
public static function allOf()
{
return new Token\LogicalAndToken(func_get_args());
}
/**
* Checks that argument array or countable object has exact number of elements.
*
* @param integer $value array elements count
*
* @return Token\ArrayCountToken
*/
public static function size($value)
{
return new Token\ArrayCountToken($value);
}
/**
* Checks that argument array contains (key, value) pair
*
* @param mixed $key exact value or token
* @param mixed $value exact value or token
*
* @return Token\ArrayEntryToken
*/
public static function withEntry($key, $value)
{
return new Token\ArrayEntryToken($key, $value);
}
/**
* Checks that arguments array entries all match value
*
* @param mixed $value
*
* @return Token\ArrayEveryEntryToken
*/
public static function withEveryEntry($value)
{
return new Token\ArrayEveryEntryToken($value);
}
/**
* Checks that argument array contains value
*
* @param mixed $value
*
* @return Token\ArrayEntryToken
*/
public static function containing($value)
{
return new Token\ArrayEntryToken(self::any(), $value);
}
/**
* Checks that argument array has key
*
* @param mixed $key exact value or token
*
* @return Token\ArrayEntryToken
*/
public static function withKey($key)
{
return new Token\ArrayEntryToken($key, self::any());
}
/**
* Checks that argument does not match the value|token.
*
* @param mixed $value either exact value or argument token
*
* @return Token\LogicalNotToken
*/
public static function not($value)
{
return new Token\LogicalNotToken($value);
}
/**
* @param string $value
*
* @return Token\StringContainsToken
*/
public static function containingString($value)
{
return new Token\StringContainsToken($value);
}
/**
* Checks that argument is identical value.
*
* @param mixed $value
*
* @return Token\IdenticalValueToken
*/
public static function is($value)
{
return new Token\IdenticalValueToken($value);
}
/**
* Check that argument is same value when rounding to the
* given precision.
*
* @param float $value
* @param float $precision
*
* @return Token\ApproximateValueToken
*/
public static function approximate($value, $precision = 0)
{
return new Token\ApproximateValueToken($value, $precision);
}
}

View File

@@ -0,0 +1,101 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument;
/**
* Arguments wildcarding.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ArgumentsWildcard
{
/**
* @var Token\TokenInterface[]
*/
private $tokens = array();
private $string;
/**
* Initializes wildcard.
*
* @param array $arguments Array of argument tokens or values
*/
public function __construct(array $arguments)
{
foreach ($arguments as $argument) {
if (!$argument instanceof Token\TokenInterface) {
$argument = new Token\ExactValueToken($argument);
}
$this->tokens[] = $argument;
}
}
/**
* Calculates wildcard match score for provided arguments.
*
* @param array $arguments
*
* @return false|int False OR integer score (higher - better)
*/
public function scoreArguments(array $arguments)
{
if (0 == count($arguments) && 0 == count($this->tokens)) {
return 1;
}
$arguments = array_values($arguments);
$totalScore = 0;
foreach ($this->tokens as $i => $token) {
$argument = isset($arguments[$i]) ? $arguments[$i] : null;
if (1 >= $score = $token->scoreArgument($argument)) {
return false;
}
$totalScore += $score;
if (true === $token->isLast()) {
return $totalScore;
}
}
if (count($arguments) > count($this->tokens)) {
return false;
}
return $totalScore;
}
/**
* Returns string representation for wildcard.
*
* @return string
*/
public function __toString()
{
if (null === $this->string) {
$this->string = implode(', ', array_map(function ($token) {
return (string) $token;
}, $this->tokens));
}
return $this->string;
}
/**
* @return array
*/
public function getTokens()
{
return $this->tokens;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument\Token;
/**
* Any single value token.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AnyValueToken implements TokenInterface
{
/**
* Always scores 3 for any argument.
*
* @param $argument
*
* @return int
*/
public function scoreArgument($argument)
{
return 3;
}
/**
* Returns false.
*
* @return bool
*/
public function isLast()
{
return false;
}
/**
* Returns string representation for token.
*
* @return string
*/
public function __toString()
{
return '*';
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument\Token;
/**
* Any values token.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class AnyValuesToken implements TokenInterface
{
/**
* Always scores 2 for any argument.
*
* @param $argument
*
* @return int
*/
public function scoreArgument($argument)
{
return 2;
}
/**
* Returns true to stop wildcard from processing other tokens.
*
* @return bool
*/
public function isLast()
{
return true;
}
/**
* Returns string representation for token.
*
* @return string
*/
public function __toString()
{
return '* [, ...]';
}
}

View File

@@ -0,0 +1,55 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument\Token;
/**
* Approximate value token
*
* @author Daniel Leech <daniel@dantleech.com>
*/
class ApproximateValueToken implements TokenInterface
{
private $value;
private $precision;
public function __construct($value, $precision = 0)
{
$this->value = $value;
$this->precision = $precision;
}
/**
* {@inheritdoc}
*/
public function scoreArgument($argument)
{
return round($argument, $this->precision) === round($this->value, $this->precision) ? 10 : false;
}
/**
* {@inheritdoc}
*/
public function isLast()
{
return false;
}
/**
* Returns string representation for token.
*
* @return string
*/
public function __toString()
{
return sprintf('≅%s', round($this->value, $this->precision));
}
}

View File

@@ -0,0 +1,86 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument\Token;
/**
* Array elements count token.
*
* @author Boris Mikhaylov <kaguxmail@gmail.com>
*/
class ArrayCountToken implements TokenInterface
{
private $count;
/**
* @param integer $value
*/
public function __construct($value)
{
$this->count = $value;
}
/**
* Scores 6 when argument has preset number of elements.
*
* @param $argument
*
* @return bool|int
*/
public function scoreArgument($argument)
{
return $this->isCountable($argument) && $this->hasProperCount($argument) ? 6 : false;
}
/**
* Returns false.
*
* @return boolean
*/
public function isLast()
{
return false;
}
/**
* Returns string representation for token.
*
* @return string
*/
public function __toString()
{
return sprintf('count(%s)', $this->count);
}
/**
* Returns true if object is either array or instance of \Countable
*
* @param $argument
* @return bool
*/
private function isCountable($argument)
{
return (is_array($argument) || $argument instanceof \Countable);
}
/**
* Returns true if $argument has expected number of elements
*
* @param array|\Countable $argument
*
* @return bool
*/
private function hasProperCount($argument)
{
return $this->count === count($argument);
}
}

View File

@@ -0,0 +1,143 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument\Token;
use Prophecy\Exception\InvalidArgumentException;
/**
* Array entry token.
*
* @author Boris Mikhaylov <kaguxmail@gmail.com>
*/
class ArrayEntryToken implements TokenInterface
{
/** @var \Prophecy\Argument\Token\TokenInterface */
private $key;
/** @var \Prophecy\Argument\Token\TokenInterface */
private $value;
/**
* @param mixed $key exact value or token
* @param mixed $value exact value or token
*/
public function __construct($key, $value)
{
$this->key = $this->wrapIntoExactValueToken($key);
$this->value = $this->wrapIntoExactValueToken($value);
}
/**
* Scores half of combined scores from key and value tokens for same entry. Capped at 8.
* If argument implements \ArrayAccess without \Traversable, then key token is restricted to ExactValueToken.
*
* @param array|\ArrayAccess|\Traversable $argument
*
* @throws \Prophecy\Exception\InvalidArgumentException
* @return bool|int
*/
public function scoreArgument($argument)
{
if ($argument instanceof \Traversable) {
$argument = iterator_to_array($argument);
}
if ($argument instanceof \ArrayAccess) {
$argument = $this->convertArrayAccessToEntry($argument);
}
if (!is_array($argument) || empty($argument)) {
return false;
}
$keyScores = array_map(array($this->key,'scoreArgument'), array_keys($argument));
$valueScores = array_map(array($this->value,'scoreArgument'), $argument);
$scoreEntry = function ($value, $key) {
return $value && $key ? min(8, ($key + $value) / 2) : false;
};
return max(array_map($scoreEntry, $valueScores, $keyScores));
}
/**
* Returns false.
*
* @return boolean
*/
public function isLast()
{
return false;
}
/**
* Returns string representation for token.
*
* @return string
*/
public function __toString()
{
return sprintf('[..., %s => %s, ...]', $this->key, $this->value);
}
/**
* Returns key
*
* @return TokenInterface
*/
public function getKey()
{
return $this->key;
}
/**
* Returns value
*
* @return TokenInterface
*/
public function getValue()
{
return $this->value;
}
/**
* Wraps non token $value into ExactValueToken
*
* @param $value
* @return TokenInterface
*/
private function wrapIntoExactValueToken($value)
{
return $value instanceof TokenInterface ? $value : new ExactValueToken($value);
}
/**
* Converts instance of \ArrayAccess to key => value array entry
*
* @param \ArrayAccess $object
*
* @return array|null
* @throws \Prophecy\Exception\InvalidArgumentException
*/
private function convertArrayAccessToEntry(\ArrayAccess $object)
{
if (!$this->key instanceof ExactValueToken) {
throw new InvalidArgumentException(sprintf(
'You can only use exact value tokens to match key of ArrayAccess object'.PHP_EOL.
'But you used `%s`.',
$this->key
));
}
$key = $this->key->getValue();
return $object->offsetExists($key) ? array($key => $object[$key]) : array();
}
}

View File

@@ -0,0 +1,82 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument\Token;
/**
* Array every entry token.
*
* @author Adrien Brault <adrien.brault@gmail.com>
*/
class ArrayEveryEntryToken implements TokenInterface
{
/**
* @var TokenInterface
*/
private $value;
/**
* @param mixed $value exact value or token
*/
public function __construct($value)
{
if (!$value instanceof TokenInterface) {
$value = new ExactValueToken($value);
}
$this->value = $value;
}
/**
* {@inheritdoc}
*/
public function scoreArgument($argument)
{
if (!$argument instanceof \Traversable && !is_array($argument)) {
return false;
}
$scores = array();
foreach ($argument as $key => $argumentEntry) {
$scores[] = $this->value->scoreArgument($argumentEntry);
}
if (empty($scores) || in_array(false, $scores, true)) {
return false;
}
return array_sum($scores) / count($scores);
}
/**
* {@inheritdoc}
*/
public function isLast()
{
return false;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return sprintf('[%s, ..., %s]', $this->value, $this->value);
}
/**
* @return TokenInterface
*/
public function getValue()
{
return $this->value;
}
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument\Token;
use Prophecy\Exception\InvalidArgumentException;
/**
* Callback-verified token.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class CallbackToken implements TokenInterface
{
private $callback;
/**
* Initializes token.
*
* @param callable $callback
*
* @throws \Prophecy\Exception\InvalidArgumentException
*/
public function __construct($callback)
{
if (!is_callable($callback)) {
throw new InvalidArgumentException(sprintf(
'Callable expected as an argument to CallbackToken, but got %s.',
gettype($callback)
));
}
$this->callback = $callback;
}
/**
* Scores 7 if callback returns true, false otherwise.
*
* @param $argument
*
* @return bool|int
*/
public function scoreArgument($argument)
{
return call_user_func($this->callback, $argument) ? 7 : false;
}
/**
* Returns false.
*
* @return bool
*/
public function isLast()
{
return false;
}
/**
* Returns string representation for token.
*
* @return string
*/
public function __toString()
{
return 'callback()';
}
}

View File

@@ -0,0 +1,116 @@
<?php
/*
* This file is part of the Prophecy.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
* Marcello Duarte <marcello.duarte@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Prophecy\Argument\Token;
use SebastianBergmann\Comparator\ComparisonFailure;
use Prophecy\Comparator\Factory as ComparatorFactory;
use Prophecy\Util\StringUtil;
/**
* Exact value token.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ExactValueToken implements TokenInterface
{
private $value;
private $string;
private $util;
private $comparatorFactory;
/**
* Initializes token.
*
* @param mixed $value
* @param StringUtil $util
* @param ComparatorFactory $comparatorFactory
*/
public function __construct($value, StringUtil $util = null, ComparatorFactory $comparatorFactory = null)
{
$this->value = $value;
$this->util = $util ?: new StringUtil();
$this->comparatorFactory = $comparatorFactory ?: ComparatorFactory::getInstance();
}
/**
* Scores 10 if argument matches preset value.
*
* @param $argument
*
* @return bool|int
*/
public function scoreArgument($argument)
{
if (is_object($argument) && is_object($this->value)) {
$comparator = $this->comparatorFactory->getComparatorFor(
$argument, $this->value
);
try {
$comparator->assertEquals($argument, $this->value);
return 10;
} catch (ComparisonFailure $failure) {}
}
// If either one is an object it should be castable to a string
if (is_object($argument) xor is_object($this->value)) {
if (is_object($argument) && !method_exists($argument, '__toString')) {
return false;
}
if (is_object($this->value) && !method_exists($this->value, '__toString')) {
return false;
}
} elseif (is_numeric($argument) && is_numeric($this->value)) {
// noop
} elseif (gettype($argument) !== gettype($this->value)) {
return false;
}
return $argument == $this->value ? 10 : false;
}
/**
* Returns preset value against which token checks arguments.
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* Returns false.
*
* @return bool
*/
public function isLast()
{
return false;
}
/**
* Returns string representation for token.
*
* @return string
*/
public function __toString()
{
if (null === $this->string) {
$this->string = sprintf('exact(%s)', $this->util->stringify($this->value));
}
return $this->string;
}
}

Some files were not shown because too many files have changed in this diff Show More