1<?php
2
3/*
4 * This file is part of the Prophecy.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6 *     Marcello Duarte <marcello.duarte@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Prophecy\Prediction;
13
14use Prophecy\Call\Call;
15use Prophecy\Prophecy\ObjectProphecy;
16use Prophecy\Prophecy\MethodProphecy;
17use Prophecy\Argument\ArgumentsWildcard;
18use Prophecy\Argument\Token\AnyValuesToken;
19use Prophecy\Util\StringUtil;
20use Prophecy\Exception\Prediction\UnexpectedCallsCountException;
21
22/**
23 * Prediction interface.
24 * Predictions are logical test blocks, tied to `should...` keyword.
25 *
26 * @author Konstantin Kudryashov <ever.zet@gmail.com>
27 */
28class CallTimesPrediction implements PredictionInterface
29{
30    private $times;
31    private $util;
32
33    /**
34     * Initializes prediction.
35     *
36     * @param int        $times
37     * @param StringUtil $util
38     */
39    public function __construct($times, StringUtil $util = null)
40    {
41        $this->times = intval($times);
42        $this->util  = $util ?: new StringUtil;
43    }
44
45    /**
46     * Tests that there was exact amount of calls made.
47     *
48     * @param Call[]         $calls
49     * @param ObjectProphecy $object
50     * @param MethodProphecy $method
51     *
52     * @throws \Prophecy\Exception\Prediction\UnexpectedCallsCountException
53     */
54    public function check(array $calls, ObjectProphecy $object, MethodProphecy $method)
55    {
56        if ($this->times == count($calls)) {
57            return;
58        }
59
60        $methodCalls = $object->findProphecyMethodCalls(
61            $method->getMethodName(),
62            new ArgumentsWildcard(array(new AnyValuesToken))
63        );
64
65        if (count($calls)) {
66            $message = sprintf(
67                "Expected exactly %d calls that match:\n".
68                "  %s->%s(%s)\n".
69                "but %d were made:\n%s",
70
71                $this->times,
72                get_class($object->reveal()),
73                $method->getMethodName(),
74                $method->getArgumentsWildcard(),
75                count($calls),
76                $this->util->stringifyCalls($calls)
77            );
78        } elseif (count($methodCalls)) {
79            $message = sprintf(
80                "Expected exactly %d calls that match:\n".
81                "  %s->%s(%s)\n".
82                "but none were made.\n".
83                "Recorded `%s(...)` calls:\n%s",
84
85                $this->times,
86                get_class($object->reveal()),
87                $method->getMethodName(),
88                $method->getArgumentsWildcard(),
89                $method->getMethodName(),
90                $this->util->stringifyCalls($methodCalls)
91            );
92        } else {
93            $message = sprintf(
94                "Expected exactly %d calls that match:\n".
95                "  %s->%s(%s)\n".
96                "but none were made.",
97
98                $this->times,
99                get_class($object->reveal()),
100                $method->getMethodName(),
101                $method->getArgumentsWildcard()
102            );
103        }
104
105        throw new UnexpectedCallsCountException($message, $method, $this->times, $calls);
106    }
107}
108