Skip to content

Instantly share code, notes, and snippets.

@docteurklein
Created August 16, 2014 19:55
Show Gist options
  • Save docteurklein/dc256bf05d284ca5e57e to your computer and use it in GitHub Desktop.
Save docteurklein/dc256bf05d284ca5e57e to your computer and use it in GitHub Desktop.
a phpspec extension to ease usage of Iterators
<?php
namespace PhpSpec\Iterator;
use PhpSpec\Wrapper\Collaborator as Base;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Promise\ReturnPromise;
class Collaborator extends Base
{
private $prophecy;
public function __construct(ObjectProphecy $prophecy, $class)
{
parent::__construct($prophecy);
$this->prophecy = $prophecy;
$this->beADoubleOf($class);
}
public function iterates(array $elements)
{
$this->prophecy->valid()->will(new ReturnPromise(array_merge(array_fill(0, count($elements), true), [false])));
$this->prophecy->count()->willReturn(count($elements));
$this->prophecy->current()->will(new ReturnPromise($elements));
$this->prophecy->next()->willReturn();
$this->prophecy->rewind()->willReturn();
}
}
<?php
namespace PhpSpec\Iterator;
use PhpSpec\Extension\ExtensionInterface;
use PhpSpec\ServiceContainer;
use PhpSpec\Iterator\Maintainer;
class Extension implements ExtensionInterface
{
public function load(ServiceContainer $container)
{
$container->setShared('runner.maintainers.iterator', function ($c) {
return new Maintainer($c->get('unwrapper'));
});
}
}
<?php
namespace PhpSpec\Iterator;
use PhpSpec\Runner\Maintainer\MaintainerInterface;
use PhpSpec\Loader\Node\ExampleNode;
use PhpSpec\SpecificationInterface;
use PhpSpec\Runner\MatcherManager;
use PhpSpec\Runner\CollaboratorManager;
use PhpSpec\Wrapper\Unwrapper;
use PhpSpec\Iterator\Collaborator;
use ReflectionClass;
use ReflectionException;
use Prophecy\Prophet;
class Maintainer implements MaintainerInterface
{
private $unwrapper;
public function __construct(Unwrapper $unwrapper)
{
$this->unwrapper = $unwrapper;
}
public function supports(ExampleNode $example)
{
return true;
return $this->hasAnyIterator($example);
}
public function prepare(ExampleNode $example, SpecificationInterface $context, MatcherManager $matchers, CollaboratorManager $collaborators)
{
$this->prophet = new Prophet(null, $this->unwrapper, null);
foreach ($this->getIterators($example) as $name => $class) {
$collaborators->set($name, new Collaborator($this->prophet->prophesize(), $class));
}
}
public function teardown(ExampleNode $example, SpecificationInterface $context, MatcherManager $matchers, CollaboratorManager $collaborators)
{
$this->prophet->checkPredictions();
}
public function getPriority()
{
return 40;
}
private function hasAnyIterator(ExampleNode $example)
{
return 0 > count($this->getIterators($example));
}
private function getIterators(ExampleNode $example)
{
$classRefl = $example->getSpecification()->getClassReflection();
if ($classRefl->hasMethod('let')) {
foreach ($classRefl->getMethod('let')->getParameters() as $parameter) {
if ($this->isIterator($parameter->getClass())) {
yield $parameter->getName() => $parameter->getClass()->getName();
}
}
}
foreach ($example->getFunctionReflection()->getParameters() as $parameter) {
if ($this->isIterator($parameter->getClass())) {
yield $parameter->getName() => $parameter->getClass()->getName();
}
}
}
private function isIterator($class)
{
try {
if (!$class instanceof ReflectionClass) {
$class = new ReflectionClass($class);
}
return $class->implementsInterface('Iterator');
}
catch (ReflectionException $e) {
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment