Skip to content

Commit

Permalink
Merge pull request #960 from Taluu/should-trigger
Browse files Browse the repository at this point in the history
Possibility to test if a php error is triggered
  • Loading branch information
ciaranmcnulty committed Oct 3, 2016
2 parents bc9b842 + 89bb79d commit 8475621
Show file tree
Hide file tree
Showing 10 changed files with 541 additions and 0 deletions.
66 changes: 66 additions & 0 deletions docs/cookbook/matchers.rst
Expand Up @@ -173,6 +173,72 @@ You can also use the Throw matcher with named constructors.
}
Trigger Matcher
---------------

Let's say you have the following class and a method which is deprecated

.. code-block:: php
<?php
class Movie
{
function setStars($value)
{
trigger_error('The method setStars is deprecated. Use setRating instead', E_USER_DEPRECATED);
$this->rating = $value * 4;
}
}
You can describe an object triggering an error using the Trigger matcher.
You use the Trigger matcher by calling it straight from ``$this``, making
the example easier to read.

.. code-block:: php
<?php
namespace spec;
use PhpSpec\ObjectBehavior;
class MovieSpec extends ObjectBehavior
{
function set_stars_should_be_deprecated()
{
$this->shouldTrigger(E_USER_DEPRECATED)->duringSetStars(4);
}
}
You may want to specify the message of the error. You can do this by
adding a string parameter to the `shouldTrigger` method :

.. code-block:: php
<?php
namespace spec;
use PhpSpec\ObjectBehavior;
class MovieSpec extends ObjectBehavior
{
function set_stars_should_be_deprecated()
{
$this->shouldTrigger(E_USER_DEPRECATED, 'The method setStars is deprecated. Use setRating instead')->duringSetRating(4);
}
}
.. note::

As with the Throw matcher, you can also use the `during` syntax described
in the Throw section, or use the instantiation mechanisms (such as
duringInstantiation, ... etc)


Type Matcher
------------

Expand Down
119 changes: 119 additions & 0 deletions features/matchers/developer_uses_trigger_matcher.feature
@@ -0,0 +1,119 @@
Feature: Developer uses trigger matcher
As a Developer
I want a trigger matcher
In order to validate triggered exceptions against my expectations

Scenario: Checking if a deprecated error has been triggered
Given the spec file "spec/Matchers/TriggerExample1/FooSpec.php" contains:
"""
<?php
namespace spec\Matchers\TriggerExample1;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class FooSpec extends ObjectBehavior
{
function it_triggers_an_error_when_calling_something_deprecated()
{
$this->shouldTrigger(E_USER_DEPRECATED)->duringDoDeprecatedStuff();
}
}
"""
And the class file "src/Matchers/TriggerExample1/Foo.php" contains:
"""
<?php
namespace Matchers\TriggerExample1;
class Foo
{
public function doDeprecatedStuff()
{
trigger_error('Foo', E_USER_DEPRECATED);
}
}
"""
When I run phpspec
Then the suite should pass

Scenario: Checking that a deprecated error has the right message
Given the spec file "spec/Matchers/TriggerExample2/FooSpec.php" contains:
"""
<?php
namespace spec\Matchers\TriggerExample3;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class FooSpec extends ObjectBehavior
{
function it_triggers_a_specific_deprecated_error_when_calling_deprecated_method()
{
$this->shouldTrigger(E_USER_DEPRECATED, 'This is deprecated')->duringDoDeprecatedStuff();
}
}
"""
And the class file "src/Matchers/TriggerExample2/Foo.php" contains:
"""
<?php
namespace Matchers\TriggerExample2;
class Foo
{
public function doDeprecatedStuff()
{
trigger_error('This is deprecated', E_USER_DEPRECATED);
}
}
"""
When I run phpspec
Then the suite should pass

Scenario: "Trigger" alias matches using the trigger matcher and let the code continue afterwards
Given the spec file "spec/Matchers/TriggerExample3/FooSpec.php" contains:
"""
<?php
namespace spec\Matchers\TriggerExample3;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class FooSpec extends ObjectBehavior
{
function it_triggers_a_deprecated_error_when_calling_deprecated_method_but_do_not_interrupt()
{
$this->shouldTrigger(E_USER_DEPRECATED, 'This is deprecated')->duringDoDeprecatedStuff(0);
$this->getDeprecated()->shouldBe(0);
}
}
"""
And the class file "src/Matchers/TriggerExample3/Foo.php" contains:
"""
<?php
namespace Matchers\TriggerExample3;
class Foo
{
private $deprecated;
public function getDeprecated()
{
return $this->deprecated;
}
public function doDeprecatedStuff($value)
{
trigger_error('This is deprecated', E_USER_DEPRECATED);
$this->deprecated = $value;
}
}
"""
When I run phpspec
Then the suite should pass

50 changes: 50 additions & 0 deletions spec/PhpSpec/Matcher/TriggerMatcherSpec.php
@@ -0,0 +1,50 @@
<?php

namespace spec\PhpSpec\Matcher;

use PhpSpec\Factory\ReflectionFactory;
use PhpSpec\ObjectBehavior;
use PhpSpec\Wrapper\Unwrapper;
use Prophecy\Argument;
use PhpSpec\Formatter\Presenter\Presenter;
use PhpSpec\Exception\Example\SkippingException;
use ArrayObject;

class TriggerMatcherSpec extends ObjectBehavior
{
function let(Unwrapper $unwrapper)
{
$unwrapper->unwrapAll(Argument::any())->willReturnArgument();

$this->beConstructedWith($unwrapper);
}

function it_supports_the_trigger_alias_for_object_and_exception_name()
{
$this->supports('trigger', '', array())->shouldReturn(true);
}

function it_accepts_a_method_during_which_an_error_should_be_triggered(ArrayObject $arr)
{
$arr->ksort()->will(function () { trigger_error('An error', E_USER_NOTICE); });

$this->positiveMatch('trigger', $arr, array(E_USER_NOTICE, 'An error'))->during('ksort', array());
}

function it_accepts_a_method_during_which_any_error_should_be_triggered(ArrayObject $arr)
{
$arr->ksort()->will(function () { trigger_error('An error', E_USER_NOTICE); });

$this->positiveMatch('trigger', $arr, array(null, null))->during('ksort', array());
}

function it_accepts_a_method_during_which_an_error_should_not_be_triggered(ArrayObject $arr)
{
$this->negativeMatch('trigger', $arr, array(E_USER_NOTICE, 'An error'))->during('ksort', array());
}

function it_accepts_a_method_during_which_any_error_should_not_be_triggered(ArrayObject $arr)
{
$this->negativeMatch('trigger', $arr, array(null, null))->during('ksort', array());
}
}
20 changes: 20 additions & 0 deletions spec/PhpSpec/Wrapper/Subject/ExpectationFactorySpec.php
Expand Up @@ -59,4 +59,24 @@ function it_creates_negative_throw_expectations(MatcherManager $matchers, Matche

$expectation->shouldHaveType('PhpSpec\Wrapper\Subject\Expectation\NegativeThrow');
}

function it_creates_positive_trigger_expectations(MatcherManager $matchers, Matcher $matcher, Subject $subject)
{
$matchers->find(Argument::cetera())->willReturn($matcher);

$subject->__call('getWrappedObject', array())->willReturn(new \stdClass());
$expectation = $this->create('shouldTrigger', $subject);

$expectation->shouldHaveType('PhpSpec\Wrapper\Subject\Expectation\PositiveTrigger');
}

function it_creates_negative_trigger_expectations(MatcherManager $matchers, Matcher $matcher, Subject $subject)
{
$matchers->find(Argument::cetera())->willReturn($matcher);

$subject->__call('getWrappedObject', array())->willReturn(new \stdClass());
$expectation = $this->create('shouldNotTrigger', $subject);

$expectation->shouldHaveType('PhpSpec\Wrapper\Subject\Expectation\NegativeTrigger');
}
}
3 changes: 3 additions & 0 deletions src/PhpSpec/Console/ContainerAssembler.php
Expand Up @@ -642,6 +642,9 @@ private function setupMatchers(IndexedServiceContainer $container)
$container->define('matchers.throwm', function (IndexedServiceContainer $c) {
return new Matcher\ThrowMatcher($c->get('unwrapper'), $c->get('formatter.presenter'), new ReflectionFactory());
}, ['matchers']);
$container->define('matchers.trigger', function (IndexedServiceContainer $c) {
return new Matcher\TriggerMatcher($c->get('unwrapper'));
}, ['matchers']);
$container->define('matchers.type', function (IndexedServiceContainer $c) {
return new Matcher\TypeMatcher($c->get('formatter.presenter'));
}, ['matchers']);
Expand Down

0 comments on commit 8475621

Please sign in to comment.