| Code Coverage
| Classes and Traits | Functions and Methods | Lines
Total | 0.00% covered (danger) | 0.00% | 0 / 1 | 12.50% covered (danger) | 12.50% | 5 / 40 | CRAP | 10.00% covered (danger) | 10.00% | 15 / 150
Expectation | 0.00% covered (danger) | 0.00% | 0 / 1 | 12.50% covered (danger) | 12.50% | 5 / 40 | 4983.80 | 10.00% covered (danger) | 10.00% | 15 / 150
__construct(\Mockery\MockInterface $mock, $name) | 100.00% covered (success) | 100.00% | 1 / 1 | 1 | 100.00% covered (success) | 100.00% | 3 / 3
__toString() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
verifyCall(array $args) | 0.00% covered (danger) | 0.00% | 0 / 1 | 20 | 0.00% covered (danger) | 0.00% | 0 / 8
_getReturnValue(array $args) | 0.00% covered (danger) | 0.00% | 0 / 1 | 30 | 0.00% covered (danger) | 0.00% | 0 / 9
isEligible() | 0.00% covered (danger) | 0.00% | 0 / 1 | 12 | 0.00% covered (danger) | 0.00% | 0 / 5
isCallCountConstrained() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
validateOrder() | 0.00% covered (danger) | 0.00% | 0 / 1 | 12 | 0.00% covered (danger) | 0.00% | 0 / 6
verify() | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 4
matchArgs(array $args) | 0.00% covered (danger) | 0.00% | 0 / 1 | 42 | 0.00% covered (danger) | 0.00% | 0 / 11
_matchArg($expected, &$actual) | 0.00% covered (danger) | 0.00% | 0 / 1 | 240 | 0.00% covered (danger) | 0.00% | 0 / 17
with() | 100.00% covered (success) | 100.00% | 1 / 1 | 1 | 100.00% covered (success) | 100.00% | 1 / 1
withArgs(array $args) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2.03 | 80.00% covered (warning) | 80.00% | 4 / 5
withNoArgs() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 3
withAnyArgs() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
andReturn() | 100.00% covered (success) | 100.00% | 1 / 1 | 1 | 100.00% covered (success) | 100.00% | 2 / 2
andReturnSelf() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
andReturnValues(array $values) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
andReturnUsing() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
andReturnUndefined() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
andReturnNull() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
andThrow($exception, $message = '', $code = 0, \Exception $previous = null) | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 6
andThrowExceptions(array $exceptions) | 0.00% covered (danger) | 0.00% | 0 / 1 | 12 | 0.00% covered (danger) | 0.00% | 0 / 6
andSet($name, $value) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
set($name, $value) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
zeroOrMoreTimes() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
times($limit = null) | 100.00% covered (success) | 100.00% | 1 / 1 | 2 | 100.00% covered (success) | 100.00% | 4 / 4
never() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
once() | 100.00% covered (success) | 100.00% | 1 / 1 | 1 | 100.00% covered (success) | 100.00% | 1 / 1
twice() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
atLeast() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
atMost() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
between($minimum, $maximum) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
ordered($group = null) | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 6
globally() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
_defineOrdered($group, $ordering) | 0.00% covered (danger) | 0.00% | 0 / 1 | 12 | 0.00% covered (danger) | 0.00% | 0 / 9
getOrderNumber() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
byDefault() | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 4
getMock() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
passthru() | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 5
__clone() | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 7

1 | <?php
2 | /**
3 | * Mockery
4 | *
5 | * LICENSE
6 | *
7 | * This source file is subject to the new BSD license that is bundled
8 | * with this package in the file LICENSE.txt.
9 | * It is also available through the world-wide-web at this URL:
10 | * http://github.com/padraic/mockery/blob/master/LICENSE
11 | * If you did not receive a copy of the license and are unable to
12 | * obtain it through the world-wide-web, please send an email
13 | * to padraic@php.net so we can send you a copy immediately.
14 | *
15 | * @category Mockery
16 | * @package Mockery
17 | * @copyright Copyright (c) 2010-2014 Pádraic Brady (http://blog.astrumfutura.com)
18 | * @license http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
19 | */
20 |
21 | namespace Mockery;
22 |
23 | class Expectation
24 | {
25 |
26 | /**
27 | * Mock object to which this expectation belongs
28 | *
29 | * @var object
30 | */
31 | protected $_mock = null;
32 |
33 | /**
34 | * Method name
35 | *
36 | * @var string
37 | */
38 | protected $_name = null;
39 |
40 | /**
41 | * Arguments expected by this expectation
42 | *
43 | * @var array
44 | */
45 | protected $_expectedArgs = array();
46 |
47 | /**
48 | * Count validator store
49 | *
50 | * @var array
51 | */
52 | protected $_countValidators = array();
53 |
54 | /**
55 | * The count validator class to use
56 | *
57 | * @var string
58 | */
59 | protected $_countValidatorClass = 'Mockery\CountValidator\Exact';
60 |
61 | /**
62 | * Actual count of calls to this expectation
63 | *
64 | * @var int
65 | */
66 | protected $_actualCount = 0;
67 |
68 | /**
69 | * Value to return from this expectation
70 | *
71 | * @var mixed
72 | */
73 | protected $_returnValue = null;
74 |
75 | /**
76 | * Array of return values as a queue for multiple return sequence
77 | *
78 | * @var array
79 | */
80 | protected $_returnQueue = array();
81 |
82 | /**
83 | * Array of closures executed with given arguments to generate a result
84 | * to be returned
85 | *
86 | * @var array
87 | */
88 | protected $_closureQueue = array();
89 |
90 | /**
91 | * Integer representing the call order of this expectation
92 | *
93 | * @var int
94 | */
95 | protected $_orderNumber = null;
96 |
97 | /**
98 | * Integer representing the call order of this expectation on a global basis
99 | *
100 | * @var int
101 | */
102 | protected $_globalOrderNumber = null;
103 |
104 | /**
105 | * Flag indicating that an exception is expected to be throw (not returned)
106 | *
107 | * @var bool
108 | */
109 | protected $_throw = false;
110 |
111 | /**
112 | * Flag indicating whether the order of calling is determined locally or
113 | * globally
114 | *
115 | * @var bool
116 | */
117 | protected $_globally = false;
118 |
119 | /**
120 | * Flag indicating we expect no arguments
121 | *
122 | * @var bool
123 | */
124 | protected $_noArgsExpectation = false;
125 |
126 | /**
127 | * Flag indicating if the return value should be obtained from the original
128 | * class method instead of returning predefined values from the return queue
129 | *
130 | * @var bool
131 | */
132 | protected $_passthru = false;
133 |
134 | /**
135 | * Constructor
136 | *
137 | * @param \Mockery\MockInterface $mock
138 | * @param string $name
139 | */
140 | public function __construct(\Mockery\MockInterface $mock, $name)
141 | {
142 | $this->_mock = $mock;
143 | $this->_name = $name;
144 | }
145 |
146 | /**
147 | * Return a string with the method name and arguments formatted
148 | *
149 | * @param string $name Name of the expected method
150 | * @param array $args List of arguments to the method
151 | * @return string
152 | */
153 | public function __toString()
154 | {
155 | return \Mockery::formatArgs($this->_name, $this->_expectedArgs);
156 | }
157 |
158 | /**
159 | * Verify the current call, i.e. that the given arguments match those
160 | * of this expectation
161 | *
162 | * @param array $args
163 | * @return mixed
164 | */
165 | public function verifyCall(array $args)
166 | {
167 | $this->validateOrder();
168 | $this->_actualCount++;
169 | if (true === $this->_passthru) {
170 | return $this->_mock->mockery_callSubjectMethod($this->_name, $args);
171 | }
172 | $return = $this->_getReturnValue($args);
173 | if ($return instanceof \Exception && $this->_throw === true) {
174 | throw $return;
175 | }
176 | return $return;
177 | }
178 |
179 | /**
180 | * Fetch the return value for the matching args
181 | *
182 | * @param array $args
183 | * @return mixed
184 | */
185 | protected function _getReturnValue(array $args)
186 | {
187 | if (count($this->_closureQueue) > 1) {
188 | return call_user_func_array(array_shift($this->_closureQueue), $args);
189 | } elseif (count($this->_closureQueue) > 0) {
190 | return call_user_func_array(current($this->_closureQueue), $args);
191 | } elseif (count($this->_returnQueue) > 1) {
192 | return array_shift($this->_returnQueue);
193 | } elseif (count($this->_returnQueue) > 0) {
194 | return current($this->_returnQueue);
195 | }
196 | }
197 |
198 | /**
199 | * Checks if this expectation is eligible for additional calls
200 | *
201 | * @return bool
202 | */
203 | public function isEligible()
204 | {
205 | foreach ($this->_countValidators as $validator) {
206 | if (!$validator->isEligible($this->_actualCount)) {
207 | return false;
208 | }
209 | }
210 | return true;
211 | }
212 |
213 | /**
214 | * Check if there is a constraint on call count
215 | *
216 | * @return bool
217 | */
218 | public function isCallCountConstrained()
219 | {
220 | return (count($this->_countValidators) > 0);
221 | }
222 |
223 | /**
224 | * Verify call order
225 | *
226 | * @return void
227 | */
228 | public function validateOrder()
229 | {
230 | if ($this->_orderNumber) {
231 | $this->_mock->mockery_validateOrder((string) $this, $this->_orderNumber, $this->_mock);
232 | }
233 | if ($this->_globalOrderNumber) {
234 | $this->_mock->mockery_getContainer()
235 | ->mockery_validateOrder((string) $this, $this->_globalOrderNumber, $this->_mock);
236 | }
237 | }
238 |
239 | /**
240 | * Verify this expectation
241 | *
242 | * @return bool
243 | */
244 | public function verify()
245 | {
246 | foreach ($this->_countValidators as $validator) {
247 | $validator->validate($this->_actualCount);
248 | }
249 | }
250 |
251 | /**
252 | * Check if passed arguments match an argument expectation
253 | *
254 | * @param array $args
255 | * @return bool
256 | */
257 | public function matchArgs(array $args)
258 | {
259 | if(empty($this->_expectedArgs) && !$this->_noArgsExpectation) {
260 | return true;
261 | }
262 | if(count($args) !== count($this->_expectedArgs)) {
263 | return false;
264 | }
265 | $argCount = count($args);
266 | for ($i=0; $i<$argCount; $i++) {
267 | $param =& $args[$i];
268 | if (!$this->_matchArg($this->_expectedArgs[$i], $param)) {
269 | return false;
270 | }
271 | }
272 |
273 | return true;
274 | }
275 |
276 | /**
277 | * Check if passed argument matches an argument expectation
278 | *
279 | * @param array $args
280 | * @return bool
281 | */
282 | protected function _matchArg($expected, &$actual)
283 | {
284 | if ($expected === $actual) {
285 | return true;
286 | }
287 | if (!is_object($expected) && !is_object($actual) && $expected == $actual) {
288 | return true;
289 | }
290 | if (is_string($expected) && !is_array($actual) && !is_object($actual)) {
291 | $result = @preg_match($expected, (string) $actual);
292 | if($result) {
293 | return true;
294 | }
295 | }
296 | if (is_string($expected) && is_object($actual)) {
297 | $result = $actual instanceof $expected;
298 | if($result) {
299 | return true;
300 | }
301 | }
302 | if ($expected instanceof \Mockery\Matcher\MatcherAbstract) {
303 | return $expected->match($actual);
304 | }
305 | if (is_a($expected, '\Hamcrest\Matcher') || is_a($expected, '\Hamcrest_Matcher')) {
306 | return $expected->matches($actual);
307 | }
308 | return false;
309 | }
310 |
311 | /**
312 | * Expected argument setter for the expectation
313 | *
314 | * @param mixed
315 | * @return self
316 | */
317 | public function with()
318 | {
319 | return $this->withArgs(func_get_args());
320 | }
321 |
322 | /**
323 | * Expected arguments for the expectation passed as an array
324 | *
325 | * @param array $args
326 | * @return self
327 | */
328 | public function withArgs(array $args)
329 | {
330 | if (empty($args)) {
331 | return $this->withNoArgs();
332 | }
333 | $this->_expectedArgs = $args;
334 | $this->_noArgsExpectation = false;
335 | return $this;
336 | }
337 |
338 | /**
339 | * Set with() as no arguments expected
340 | *
341 | * @return self
342 | */
343 | public function withNoArgs()
344 | {
345 | $this->_noArgsExpectation = true;
346 | $this->_expectedArgs = null;
347 | return $this;
348 | }
349 |
350 | /**
351 | * Set expectation that any arguments are acceptable
352 | *
353 | * @return self
354 | */
355 | public function withAnyArgs()
356 | {
357 | $this->_expectedArgs = array();
358 | return $this;
359 | }
360 |
361 | /**
362 | * Set a return value, or sequential queue of return values
363 | *
364 | * @return self
365 | */
366 | public function andReturn()
367 | {
368 | $this->_returnQueue = func_get_args();
369 | return $this;
370 | }
371 |
372 | /**
373 | * Return this mock, like a fluent interface
374 | *
375 | * @return self
376 | */
377 | public function andReturnSelf()
378 | {
379 | return $this->andReturn($this->_mock);
380 | }
381 |
382 | /**
383 | * Set a sequential queue of return values with an array
384 | *
385 | * @return self
386 | */
387 | public function andReturnValues(array $values)
388 | {
389 | call_user_func_array(array($this, 'andReturn'), $values);
390 | return $this;
391 | }
392 |
393 | /**
394 | * Set a closure or sequence of closures with which to generate return
395 | * values. The arguments passed to the expected method are passed to the
396 | * closures as parameters.
397 | *
398 | * @return self
399 | */
400 | public function andReturnUsing()
401 | {
402 | $this->_closureQueue = func_get_args();
403 | return $this;
404 | }
405 |
406 | /**
407 | * Return a self-returning black hole object.
408 | *
409 | * @return self
410 | */
411 | public function andReturnUndefined()
412 | {
413 | $this->andReturn(new \Mockery\Undefined);
414 | return $this;
415 | }
416 |
417 | /**
418 | * Return null. This is merely a language construct for Mock describing.
419 | *
420 | * @return self
421 | */
422 | public function andReturnNull()
423 | {
424 | return $this;
425 | }
426 |
427 | /**
428 | * Set Exception class and arguments to that class to be thrown
429 | *
430 | * @param string $exception
431 | * @param string $message
432 | * @param int $code
433 | * @param Exception $previous
434 | * @return self
435 | */
436 | public function andThrow($exception, $message = '', $code = 0, \Exception $previous = null)
437 | {
438 | $this->_throw = true;
439 | if (is_object($exception)) {
440 | $this->andReturn($exception);
441 | } else {
442 | $this->andReturn(new $exception($message, $code, $previous));
443 | }
444 | return $this;
445 | }
446 |
447 | /**
448 | * Set Exception classes to be thrown
449 | *
450 | * @param array $exceptions
451 | * @return self
452 | */
453 | public function andThrowExceptions(array $exceptions)
454 | {
455 | $this->_throw = true;
456 | foreach ($exceptions as $exception) {
457 | if (!is_object($exception)) {
458 | throw new Exception('You must pass an array of exception objects to andThrowExceptions');
459 | }
460 | }
461 | return $this->andReturnValues($exceptions);
462 | }
463 |
464 | /**
465 | * Set a public property on the mock
466 | *
467 | * @param string $name
468 | * @param mixed $value
469 | * @return self
470 | */
471 | public function andSet($name, $value)
472 | {
473 | $this->_mock->{$name} = $value;
474 | return $this;
475 | }
476 |
477 | /**
478 | * Set a public property on the mock (alias to andSet()). Allows the natural
479 | * English construct - set('foo', 'bar')->andReturn('bar')
480 | *
481 | * @param string $name
482 | * @param mixed $value
483 | * @return self
484 | */
485 | public function set($name, $value)
486 | {
487 | return $this->andSet($name, $value);
488 | }
489 |
490 | /**
491 | * Indicates this expectation should occur zero or more times
492 | *
493 | * @return self
494 | */
495 | public function zeroOrMoreTimes()
496 | {
497 | $this->atLeast()->never();
498 | }
499 |
500 | /**
501 | * Indicates the number of times this expectation should occur
502 | *
503 | * @param int $limit
504 | */
505 | public function times($limit = null)
506 | {
507 | if (is_null($limit)) return $this;
508 | $this->_countValidators[] = new $this->_countValidatorClass($this, $limit);
509 | $this->_countValidatorClass = 'Mockery\CountValidator\Exact';
510 | return $this;
511 | }
512 |
513 | /**
514 | * Indicates that this expectation is never expected to be called
515 | *
516 | * @return self
517 | */
518 | public function never()
519 | {
520 | return $this->times(0);
521 | }
522 |
523 | /**
524 | * Indicates that this expectation is expected exactly once
525 | *
526 | * @return self
527 | */
528 | public function once()
529 | {
530 | return $this->times(1);
531 | }
532 |
533 | /**
534 | * Indicates that this expectation is expected exactly twice
535 | *
536 | * @return self
537 | */
538 | public function twice()
539 | {
540 | return $this->times(2);
541 | }
542 |
543 | /**
544 | * Sets next count validator to the AtLeast instance
545 | *
546 | * @return self
547 | */
548 | public function atLeast()
549 | {
550 | $this->_countValidatorClass = 'Mockery\CountValidator\AtLeast';
551 | return $this;
552 | }
553 |
554 | /**
555 | * Sets next count validator to the AtMost instance
556 | *
557 | * @return self
558 | */
559 | public function atMost()
560 | {
561 | $this->_countValidatorClass = 'Mockery\CountValidator\AtMost';
562 | return $this;
563 | }
564 |
565 | /**
566 | * Shorthand for setting minimum and maximum constraints on call counts
567 | *
568 | * @param int $minimum
569 | * @param int $maximum
570 | */
571 | public function between($minimum, $maximum)
572 | {
573 | return $this->atLeast()->times($minimum)->atMost()->times($maximum);
574 | }
575 |
576 | /**
577 | * Indicates that this expectation must be called in a specific given order
578 | *
579 | * @param string $group Name of the ordered group
580 | * @return self
581 | */
582 | public function ordered($group = null)
583 | {
584 | if ($this->_globally) {
585 | $this->_globalOrderNumber = $this->_defineOrdered($group, $this->_mock->mockery_getContainer());
586 | } else {
587 | $this->_orderNumber = $this->_defineOrdered($group, $this->_mock);
588 | }
589 | $this->_globally = false;
590 | return $this;
591 | }
592 |
593 | /**
594 | * Indicates call order should apply globally
595 | *
596 | * @return self
597 | */
598 | public function globally()
599 | {
600 | $this->_globally = true;
601 | return $this;
602 | }
603 |
604 | /**
605 | * Setup the ordering tracking on the mock or mock container
606 | *
607 | * @param string $group
608 | * @param object $ordering
609 | * @return int
610 | */
611 | protected function _defineOrdered($group, $ordering)
612 | {
613 | $groups = $ordering->mockery_getGroups();
614 | if (is_null($group)) {
615 | $result = $ordering->mockery_allocateOrder();
616 | } elseif (isset($groups[$group])) {
617 | $result = $groups[$group];
618 | } else {
619 | $result = $ordering->mockery_allocateOrder();
620 | $ordering->mockery_setGroup($group, $result);
621 | }
622 | return $result;
623 | }
624 |
625 | /**
626 | * Return order number
627 | *
628 | * @return int
629 | */
630 | public function getOrderNumber()
631 | {
632 | return $this->_orderNumber;
633 | }
634 |
635 | /**
636 | * Mark this expectation as being a default
637 | *
638 | * @return self
639 | */
640 | public function byDefault()
641 | {
642 | $director = $this->_mock->mockery_getExpectationsFor($this->_name);
643 | if(!empty($director)) {
644 | $director->makeExpectationDefault($this);
645 | }
646 | return $this;
647 | }
648 |
649 | /**
650 | * Return the parent mock of the expectation
651 | *
652 | * @return \Mockery\MockInterface
653 | */
654 | public function getMock()
655 | {
656 | return $this->_mock;
657 | }
658 |
659 | /**
660 | * Flag this expectation as calling the original class method with the
661 | * any provided arguments instead of using a return value queue.
662 | *
663 | * @return self
664 | */
665 | public function passthru()
666 | {
667 | if ($this->_mock instanceof Mock) {
668 | throw new Exception(
669 | 'Mock Objects not created from a loaded/existing class are '
670 | . 'incapable of passing method calls through to a parent class'
671 | );
672 | }
673 | $this->_passthru = true;
674 | return $this;
675 | }
676 |
677 | /**
678 | * Cloning logic
679 | *
680 | */
681 | public function __clone()
682 | {
683 | $newValidators = array();
684 | $countValidators = $this->_countValidators;
685 | foreach ($countValidators as $validator) {
686 | $newValidators[] = clone $validator;
687 | }
688 | $this->_countValidators = $newValidators;
689 | }
690 |
691 | }