Completed
Push — master ( 6bbd38...55e0d1 )
by Erin
10s
created

src/Matcher/ExceptionMatcher.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Peridot\Leo\Matcher;
3
4
use Peridot\Leo\Matcher\Template\ArrayTemplate;
5
use Peridot\Leo\Matcher\Template\TemplateInterface;
6
7
/**
8
 * ExceptionMatcher executes a callable and determines if an exception of a given type was thrown. It optionally
9
 * matches the exception message.
10
 *
11
 * @package Peridot\Leo\Matcher
12
 */
13
class ExceptionMatcher extends AbstractMatcher
14
{
15
    /**
16
     * @var array
17
     */
18
    protected $arguments = [];
19
20
    /**
21
     * @var string
22
     */
23
    protected $expectedMessage = "";
24
25
    /**
26
     * A captured exception message
27
     *
28
     * @var string $message
29
     */
30
    protected $message;
31
32
    /**
33
     * @var TemplateInterface
34
     */
35
    protected $messageTemplate;
36
37
    /**
38
     * @param callable $expected
0 ignored issues
show
There is no parameter named $expected. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
39
     */
40
    public function __construct($exceptionType)
41
    {
42
        $this->expected = $exceptionType;
43
    }
44
45
    /**
46
     * Set arguments to be passed to the callable.
47
     *
48
     * @param array $arguments
49
     * @return $this
50
     */
51
    public function setArguments(array $arguments)
52
    {
53
        $this->arguments = $arguments;
54
        return $this;
55
    }
56
57
    /**
58
     * Set the expected message of the exception.
59
     *
60
     * @param string $message
61
     * @return $this
62
     */
63
    public function setExpectedMessage($message)
64
    {
65
        $this->expectedMessage = $message;
66
        return $this;
67
    }
68
69
    /**
70
     * Set the message thrown from an exception resulting from the
71
     * callable being invoked.
72
     *
73
     * @param string $message
74
     */
75
    public function setMessage($message)
76
    {
77
        $this->message = $message;
78
    }
79
80
    /**
81
     * Returns the arguments passed to the callable.
82
     *
83
     * @return array
84
     */
85
    public function getArguments()
86
    {
87
        return $this->arguments;
88
    }
89
90
    /**
91
     * Return the expected exception message.
92
     *
93
     * @return string
94
     */
95
    public function getExpectedMessage()
96
    {
97
        return $this->expectedMessage;
98
    }
99
100
    /**
101
     * Return the message thrown by an exception resulting from the callable
102
     * being invoked.
103
     *
104
     * @return string
105
     */
106
    public function getMessage()
107
    {
108
        return $this->message;
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     *
114
     * If the expected message has been set, the message template will be used.
115
     *
116
     * @return TemplateInterface
117
     */
118
    public function getTemplate()
119
    {
120
        if ($this->expectedMessage) {
121
            return $this->getMessageTemplate();
122
        }
123
        return parent::getTemplate();
124
    }
125
126
    /**
127
     * Set the template to be used when an expected exception message is provided.
128
     *
129
     * @param TemplateInterface $template
130
     * @return $this
131
     */
132
    public function setMessageTemplate(TemplateInterface $template)
133
    {
134
        $this->messageTemplate = $template;
135
        return $this;
136
    }
137
138
    /**
139
     * Return a template for rendering exception message templates.
140
     *
141
     * return TemplateInterface
142
     */
143
    public function getMessageTemplate()
144
    {
145
        if ($this->messageTemplate) {
146
            return $this->messageTemplate;
147
        }
148
        return $this->getDefaultMessageTemplate();
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     *
154
     * @return TemplateInterface
155
     */
156
    public function getDefaultTemplate()
157
    {
158
        $template = new ArrayTemplate([
159
            'default' => 'Expected exception of type {{expected}}',
160
            'negated' => 'Expected type of exception not to be {{expected}}'
161
        ]);
162
163
        return $template;
164
    }
165
166
    /**
167
     * Return a default template for exception message assertions.
168
     *
169
     * @return ArrayTemplate
170
     */
171
    public function getDefaultMessageTemplate()
172
    {
173
        return new ArrayTemplate([
174
            'default' => 'Expected exception message {{expected}}, got {{actual}}',
175
            'negated' => 'Expected exception message {{actual}} not to equal {{expected}}'
176
        ]);
177
    }
178
179
    /**
180
     * Override match to set actual and expect match values to message
181
     * values.
182
     *
183
     * @param $actual
184
     * @return Match
185
     */
186
    public function match($actual)
187
    {
188
        $match = parent::match($actual);
189
        if ($this->expectedMessage) {
190
            $match->setActual($this->message);
191
            $match->setExpected($this->expectedMessage);
192
        }
193
        return $match;
194
    }
195
196
    /**
197
     * Executes the callable and matches the exception type and exception message.
198
     *
199
     * @param $actual
200
     * @return bool
201
     */
202
    protected function doMatch($actual)
203
    {
204
        $this->validateCallable($actual);
205
        try {
206
            call_user_func_array($actual, $this->arguments);
207
            return false;
208
        } catch (\Exception $e) {
209
            $message = $e->getMessage();
210
            if ($this->expectedMessage) {
211
                $this->setMessage($message);
212
                return $this->expectedMessage == $message;
213
            }
214
            if (!$e instanceof $this->expected) {
215
                return false;
216
            }
217
        }
218
        return true;
219
    }
220
221
    /**
222
     * Validate that expected is indeed a valid callable.
223
     *
224
     * @throws \BadFunctionCallException
225
     */
226
    protected function validateCallable($callable)
227
    {
228
        if (!is_callable($callable)) {
229
            $callable = rtrim(print_r($callable, true));
230
            throw new \BadFunctionCallException("Invalid callable " . $callable . " given");
231
        }
232
    }
233
}
234