File: Mock.php

package info (click to toggle)
php-mock 2.6.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 340 kB
  • sloc: php: 1,740; makefile: 18; xml: 17; sh: 7
file content (190 lines) | stat: -rw-r--r-- 4,828 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
<?php

namespace phpmock;

use InvalidArgumentException;
use phpmock\generator\MockFunctionGenerator;

/**
 * Mocking framework for built-in PHP functions.
 *
 * Mocking a build-in PHP function is achieved by using
 * PHP's namespace fallback policy. A mock will provide the namespaced function.
 * I.e. only unqualified functions in a non-global namespace can be mocked.
 *
 * Example:
 * <code>
 * namespace foo;
 *
 * use phpmock\Mock;
 *
 * $time = new Mock(
 *     __NAMESPACE__,
 *     "time",
 *     function () {
 *         return 3;
 *     }
 * );
 * $time->enable();
 * assert (3 == time());
 *
 * $time->disable();
 * assert (3 != time());
 * </code>
 *
 * @author Markus Malkusch <markus@malkusch.de>
 * @link bitcoin:1335STSwu9hST4vcMRppEPgENMHD2r1REK Donations
 * @license http://www.wtfpl.net/txt/copying/ WTFPL
 * @see MockBuilder
 */
class Mock implements Deactivatable
{
    /**
     * @var string namespace for the mock function.
     */
    private $namespace;

    /**
     * @var string function name of the mocked function.
     */
    private $name;

    /**
     * @var callable The function mock.
     */
    private $function;

    /**
     * Set the namespace, function name and the mock function.
     *
     * @param string   $namespace  The namespace for the mock function.
     * @param string   $name       The function name of the mocked function.
     * @param callable $function   The mock function.
     */
    public function __construct($namespace, $name, callable $function)
    {
        if (empty($namespace)) {
            throw new InvalidArgumentException('Namespace should not be empty');
        }
        if (empty($name)) {
            throw new InvalidArgumentException('Function name should not be empty');
        }

        $this->namespace = $namespace;
        $this->name      = $name;
        $this->function  = $function;
    }

    /**
     * Enables this mock.
     *
     * @throws MockEnabledException If the function has already an enabled mock.
     * @see Mock::disable()
     * @see Mock::disableAll()
     *
     * @SuppressWarnings(PHPMD)
     */
    public function enable()
    {
        $registry = MockRegistry::getInstance();
        if ($registry->isRegistered($this)) {
            throw new MockEnabledException(
                "$this->name is already enabled."
                . " Call disable() on the existing mock."
            );
        }
        $this->define();
        $registry->register($this);
    }

    /**
     * Disable this mock.
     *
     * @see Mock::enable()
     * @see Mock::disableAll()
     */
    public function disable()
    {
        MockRegistry::getInstance()->unregister($this);
    }

    /**
     * Disable all mocks.
     *
     * @see Mock::enable()
     * @see Mock::disable()
     */
    public static function disableAll()
    {
        MockRegistry::getInstance()->unregisterAll();
    }

    /**
     * Calls the mocked function.
     *
     * This method is called from the namespaced function.
     *
     * @param array $arguments the call arguments.
     * @return mixed
     * @internal
     */
    public function call(array $arguments)
    {
        return call_user_func_array($this->function, $arguments);
    }

    /**
     * Returns the fully qualified function name.
     *
     * @return string The function name with its namespace.
     * @internal
     */
    public function getFQFN()
    {
        return strtolower("{$this->getNamespace()}\\$this->name");
    }

    /**
     * Returns the namespace without enclosing slashes.
     *
     * @return string The namespace
     */
    public function getNamespace()
    {
        return trim($this->namespace, "\\");
    }

    /**
     * Returns the unqualified function name.
     *
     * @return string The name of the mocked function.
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Defines the mocked function in the given namespace.
     *
     * In most cases you don't have to call this method. enable() is doing this
     * for you. But if the mock is defined after the first call in the
     * tested class, the tested class doesn't resolve to the mock. This is
     * documented in Bug #68541. You therefore have to define the namespaced
     * function before the first call. Defining the function has no side
     * effects as you still have to enable the mock. If the function was
     * already defined this method does nothing.
     *
     * @see enable()
     * @link https://bugs.php.net/bug.php?id=68541 Bug #68541
     */
    public function define()
    {
        $fqfn = $this->getFQFN();
        if (function_exists($fqfn)) {
            return;
        }
        $functionGenerator = new MockFunctionGenerator($this);
        $functionGenerator->defineFunction();
    }
}