1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
20:
21: namespace Mockery;
22:
23: class Expectation implements ExpectationInterface
24: {
25:
26: 27: 28: 29: 30:
31: protected $_mock = null;
32:
33: 34: 35: 36: 37:
38: protected $_name = null;
39:
40: 41: 42: 43: 44:
45: protected $_expectedArgs = array();
46:
47: 48: 49: 50: 51:
52: protected $_countValidators = array();
53:
54: 55: 56: 57: 58:
59: protected $_countValidatorClass = 'Mockery\CountValidator\Exact';
60:
61: 62: 63: 64: 65:
66: protected $_actualCount = 0;
67:
68: 69: 70: 71: 72:
73: protected $_returnValue = null;
74:
75: 76: 77: 78: 79:
80: protected $_returnQueue = array();
81:
82: 83: 84: 85: 86: 87:
88: protected $_closureQueue = array();
89:
90: 91: 92: 93: 94:
95: protected $_setQueue = array();
96:
97: 98: 99: 100: 101:
102: protected $_orderNumber = null;
103:
104: 105: 106: 107: 108:
109: protected $_globalOrderNumber = null;
110:
111: 112: 113: 114: 115:
116: protected $_throw = false;
117:
118: 119: 120: 121: 122: 123:
124: protected $_globally = false;
125:
126: 127: 128: 129: 130:
131: protected $_noArgsExpectation = false;
132:
133: 134: 135: 136: 137: 138:
139: protected $_passthru = false;
140:
141: 142: 143: 144: 145: 146:
147: public function __construct(\Mockery\MockInterface $mock, $name)
148: {
149: $this->_mock = $mock;
150: $this->_name = $name;
151: }
152:
153: 154: 155: 156: 157: 158: 159:
160: public function __toString()
161: {
162: return \Mockery::formatArgs($this->_name, $this->_expectedArgs);
163: }
164:
165: 166: 167: 168: 169: 170: 171:
172: public function verifyCall(array $args)
173: {
174: $this->validateOrder();
175: $this->_actualCount++;
176: if (true === $this->_passthru) {
177: return $this->_mock->mockery_callSubjectMethod($this->_name, $args);
178: }
179: $return = $this->_getReturnValue($args);
180: if ($return instanceof \Exception && $this->_throw === true) {
181: throw $return;
182: }
183: $this->_setValues();
184: return $return;
185: }
186:
187: 188: 189: 190: 191: 192:
193: protected function _setValues()
194: {
195: foreach ($this->_setQueue as $name => &$values) {
196: if (count($values) > 0) {
197: $value = array_shift($values);
198: $this->_mock->{$name} = $value;
199: }
200: }
201: }
202:
203: 204: 205: 206: 207: 208:
209: protected function _getReturnValue(array $args)
210: {
211: if (count($this->_closureQueue) > 1) {
212: return call_user_func_array(array_shift($this->_closureQueue), $args);
213: } elseif (count($this->_closureQueue) > 0) {
214: return call_user_func_array(current($this->_closureQueue), $args);
215: } elseif (count($this->_returnQueue) > 1) {
216: return array_shift($this->_returnQueue);
217: } elseif (count($this->_returnQueue) > 0) {
218: return current($this->_returnQueue);
219: }
220: }
221:
222: 223: 224: 225: 226:
227: public function isEligible()
228: {
229: foreach ($this->_countValidators as $validator) {
230: if (!$validator->isEligible($this->_actualCount)) {
231: return false;
232: }
233: }
234: return true;
235: }
236:
237: 238: 239: 240: 241:
242: public function isCallCountConstrained()
243: {
244: return (count($this->_countValidators) > 0);
245: }
246:
247: 248: 249: 250: 251:
252: public function validateOrder()
253: {
254: if ($this->_orderNumber) {
255: $this->_mock->mockery_validateOrder((string) $this, $this->_orderNumber, $this->_mock);
256: }
257: if ($this->_globalOrderNumber) {
258: $this->_mock->mockery_getContainer()
259: ->mockery_validateOrder((string) $this, $this->_globalOrderNumber, $this->_mock);
260: }
261: }
262:
263: 264: 265: 266: 267:
268: public function verify()
269: {
270: foreach ($this->_countValidators as $validator) {
271: $validator->validate($this->_actualCount);
272: }
273: }
274:
275: 276: 277: 278: 279: 280:
281: public function matchArgs(array $args)
282: {
283: if(empty($this->_expectedArgs) && !$this->_noArgsExpectation) {
284: return true;
285: }
286: if(count($args) !== count($this->_expectedArgs)) {
287: return false;
288: }
289: $argCount = count($args);
290: for ($i=0; $i<$argCount; $i++) {
291: $param =& $args[$i];
292: if (!$this->_matchArg($this->_expectedArgs[$i], $param)) {
293: return false;
294: }
295: }
296:
297: return true;
298: }
299:
300: 301: 302: 303: 304: 305:
306: protected function _matchArg($expected, &$actual)
307: {
308: if ($expected === $actual) {
309: return true;
310: }
311: if (!is_object($expected) && !is_object($actual) && $expected == $actual) {
312: return true;
313: }
314: if (is_string($expected) && !is_array($actual) && !is_object($actual)) {
315:
316: set_error_handler(function () {});
317: $result = preg_match($expected, (string) $actual);
318: restore_error_handler();
319:
320: if($result) {
321: return true;
322: }
323: }
324: if (is_string($expected) && is_object($actual)) {
325: $result = $actual instanceof $expected;
326: if($result) {
327: return true;
328: }
329: }
330: if ($expected instanceof \Mockery\Matcher\MatcherAbstract) {
331: return $expected->match($actual);
332: }
333: if (is_a($expected, '\Hamcrest\Matcher') || is_a($expected, '\Hamcrest_Matcher')) {
334: return $expected->matches($actual);
335: }
336: return false;
337: }
338:
339: 340: 341: 342: 343: 344:
345: public function with()
346: {
347: return $this->withArgs(func_get_args());
348: }
349:
350: 351: 352: 353: 354: 355:
356: public function withArgs(array $args)
357: {
358: if (empty($args)) {
359: return $this->withNoArgs();
360: }
361: $this->_expectedArgs = $args;
362: $this->_noArgsExpectation = false;
363: return $this;
364: }
365:
366: 367: 368: 369: 370:
371: public function withNoArgs()
372: {
373: $this->_noArgsExpectation = true;
374: $this->_expectedArgs = null;
375: return $this;
376: }
377:
378: 379: 380: 381: 382:
383: public function withAnyArgs()
384: {
385: $this->_expectedArgs = array();
386: return $this;
387: }
388:
389: 390: 391: 392: 393:
394: public function andReturn()
395: {
396: $this->_returnQueue = func_get_args();
397: return $this;
398: }
399:
400: 401: 402: 403: 404:
405: public function andReturnSelf()
406: {
407: return $this->andReturn($this->_mock);
408: }
409:
410: 411: 412: 413: 414: 415:
416: public function andReturnValues(array $values)
417: {
418: call_user_func_array(array($this, 'andReturn'), $values);
419: return $this;
420: }
421:
422: 423: 424: 425: 426: 427: 428:
429: public function andReturnUsing()
430: {
431: $this->_closureQueue = func_get_args();
432: return $this;
433: }
434:
435: 436: 437: 438: 439:
440: public function andReturnUndefined()
441: {
442: $this->andReturn(new \Mockery\Undefined);
443: return $this;
444: }
445:
446: 447: 448: 449: 450:
451: public function andReturnNull()
452: {
453: return $this;
454: }
455:
456: 457: 458: 459: 460: 461: 462: 463: 464:
465: public function andThrow($exception, $message = '', $code = 0, \Exception $previous = null)
466: {
467: $this->_throw = true;
468: if (is_object($exception)) {
469: $this->andReturn($exception);
470: } else {
471: $this->andReturn(new $exception($message, $code, $previous));
472: }
473: return $this;
474: }
475:
476: 477: 478: 479: 480: 481:
482: public function andThrowExceptions(array $exceptions)
483: {
484: $this->_throw = true;
485: foreach ($exceptions as $exception) {
486: if (!is_object($exception)) {
487: throw new Exception('You must pass an array of exception objects to andThrowExceptions');
488: }
489: }
490: return $this->andReturnValues($exceptions);
491: }
492:
493: 494: 495: 496: 497: 498: 499:
500: public function andSet($name, $value)
501: {
502: $values = func_get_args();
503: array_shift($values);
504: $this->_setQueue[$name] = $values;
505: return $this;
506: }
507:
508: 509: 510: 511: 512: 513: 514: 515:
516: public function set($name, $value)
517: {
518: return call_user_func_array(array($this, 'andSet'), func_get_args());
519: }
520:
521: 522: 523: 524: 525:
526: public function zeroOrMoreTimes()
527: {
528: $this->atLeast()->never();
529: }
530:
531: 532: 533: 534: 535:
536: public function times($limit = null)
537: {
538: if (is_null($limit)) return $this;
539: $this->_countValidators[] = new $this->_countValidatorClass($this, $limit);
540: $this->_countValidatorClass = 'Mockery\CountValidator\Exact';
541: return $this;
542: }
543:
544: 545: 546: 547: 548:
549: public function never()
550: {
551: return $this->times(0);
552: }
553:
554: 555: 556: 557: 558:
559: public function once()
560: {
561: return $this->times(1);
562: }
563:
564: 565: 566: 567: 568:
569: public function twice()
570: {
571: return $this->times(2);
572: }
573:
574: 575: 576: 577: 578:
579: public function atLeast()
580: {
581: $this->_countValidatorClass = 'Mockery\CountValidator\AtLeast';
582: return $this;
583: }
584:
585: 586: 587: 588: 589:
590: public function atMost()
591: {
592: $this->_countValidatorClass = 'Mockery\CountValidator\AtMost';
593: return $this;
594: }
595:
596: 597: 598: 599: 600: 601:
602: public function between($minimum, $maximum)
603: {
604: return $this->atLeast()->times($minimum)->atMost()->times($maximum);
605: }
606:
607: 608: 609: 610: 611: 612:
613: public function ordered($group = null)
614: {
615: if ($this->_globally) {
616: $this->_globalOrderNumber = $this->_defineOrdered($group, $this->_mock->mockery_getContainer());
617: } else {
618: $this->_orderNumber = $this->_defineOrdered($group, $this->_mock);
619: }
620: $this->_globally = false;
621: return $this;
622: }
623:
624: 625: 626: 627: 628:
629: public function globally()
630: {
631: $this->_globally = true;
632: return $this;
633: }
634:
635: 636: 637: 638: 639: 640: 641:
642: protected function _defineOrdered($group, $ordering)
643: {
644: $groups = $ordering->mockery_getGroups();
645: if (is_null($group)) {
646: $result = $ordering->mockery_allocateOrder();
647: } elseif (isset($groups[$group])) {
648: $result = $groups[$group];
649: } else {
650: $result = $ordering->mockery_allocateOrder();
651: $ordering->mockery_setGroup($group, $result);
652: }
653: return $result;
654: }
655:
656: 657: 658: 659: 660:
661: public function getOrderNumber()
662: {
663: return $this->_orderNumber;
664: }
665:
666: 667: 668: 669: 670:
671: public function byDefault()
672: {
673: $director = $this->_mock->mockery_getExpectationsFor($this->_name);
674: if(!empty($director)) {
675: $director->makeExpectationDefault($this);
676: }
677: return $this;
678: }
679:
680: 681: 682: 683: 684:
685: public function getMock()
686: {
687: return $this->_mock;
688: }
689:
690: 691: 692: 693: 694: 695:
696: public function passthru()
697: {
698: if ($this->_mock instanceof Mock) {
699: throw new Exception(
700: 'Mock Objects not created from a loaded/existing class are '
701: . 'incapable of passing method calls through to a parent class'
702: );
703: }
704: $this->_passthru = true;
705: return $this;
706: }
707:
708: 709: 710: 711:
712: public function __clone()
713: {
714: $newValidators = array();
715: $countValidators = $this->_countValidators;
716: foreach ($countValidators as $validator) {
717: $newValidators[] = clone $validator;
718: }
719: $this->_countValidators = $newValidators;
720: }
721:
722: public function getName()
723: {
724: return $this->_name;
725: }
726:
727: }
728: