| Code Coverage
| Classes and Traits | Functions and Methods | Lines
Total | 0.00% covered (danger) | 0.00% | 0 / 1 | 13.64% covered (danger) | 13.64% | 3 / 22 | CRAP | 28.80% covered (danger) | 28.80% | 53 / 184
Container | 0.00% covered (danger) | 0.00% | 0 / 1 | 13.64% covered (danger) | 13.64% | 3 / 22 | 2104.94 | 28.80% covered (danger) | 28.80% | 53 / 184
__construct(Generator $generator = null, LoaderInterface $loader = null) | 100.00% covered (success) | 100.00% | 1 / 1 | 3 | 100.00% covered (success) | 100.00% | 3 / 3
mock() | 0.00% covered (danger) | 0.00% | 0 / 1 | 403.65 | 36.73% covered (danger) | 36.73% | 36 / 98
instanceMock() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
getLoader() | 100.00% covered (success) | 100.00% | 1 / 1 | 1 | 100.00% covered (success) | 100.00% | 1 / 1
getGenerator() | 100.00% covered (success) | 100.00% | 1 / 1 | 1 | 100.00% covered (success) | 100.00% | 1 / 1
mockery_teardown() | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 5
mockery_verify() | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 4
mockery_close() | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 5
mockery_allocateOrder() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
mockery_setGroup($group, $order) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
mockery_getGroups() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
mockery_setCurrentOrder($order) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
mockery_getCurrentOrder() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 1
mockery_validateOrder($method, $order, \Mockery\MockInterface $mock) | 0.00% covered (danger) | 0.00% | 0 / 1 | 5.08 | 8.33% covered (danger) | 8.33% | 1 / 12
mockery_getExpectationCount() | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 5
rememberMock(\Mockery\MockInterface $mock) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2.03 | 80.00% covered (warning) | 80.00% | 4 / 5
self() | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 3
fetchMock($reference) | 0.00% covered (danger) | 0.00% | 0 / 1 | 6 | 0.00% covered (danger) | 0.00% | 0 / 2
_getInstance($mockName, $constructorArgs = null) | 0.00% covered (danger) | 0.00% | 0 / 1 | 4.12 | 50.00% covered (warning) | 50.00% | 4 / 8
declareClass($fqcn) | 0.00% covered (danger) | 0.00% | 0 / 1 | 12 | 0.00% covered (danger) | 0.00% | 0 / 4
anonymous function ($part) | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 | 0.00% covered (danger) | 0.00% | 0 / 2
checkForNamedMockClashes($config) | 0.00% covered (danger) | 0.00% | 0 / 1 | 10.15 | 27.27% covered (danger) | 27.27% | 3 / 11

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 | use Mockery\Generator\Generator;
24 | use Mockery\Generator\MockConfigurationBuilder;
25 | use Mockery\Loader\Loader as LoaderInterface;
26 |
27 | class Container
28 | {
29 | const BLOCKS = \Mockery::BLOCKS;
30 |
31 | /**
32 | * Store of mock objects
33 | *
34 | * @var array
35 | */
36 | protected $_mocks = array();
37 |
38 | /**
39 | * Order number of allocation
40 | *
41 | * @var int
42 | */
43 | protected $_allocatedOrder = 0;
44 |
45 | /**
46 | * Current ordered number
47 | *
48 | * @var int
49 | */
50 | protected $_currentOrder = 0;
51 |
52 | /**
53 | * Ordered groups
54 | *
55 | * @var array
56 | */
57 | protected $_groups = array();
58 |
59 | /**
60 | * @var Generator\Generator
61 | */
62 | protected $_generator;
63 |
64 | /**
65 | * @var LoaderInterface
66 | */
67 | protected $_loader;
68 |
69 | /**
70 | * @var array
71 | */
72 | protected $_namedMocks = array();
73 |
74 | public function __construct(Generator $generator = null, LoaderInterface $loader = null)
75 | {
76 | $this->_generator = $generator ?: \Mockery::getDefaultGenerator();
77 | $this->_loader = $loader ?: \Mockery::getDefaultLoader();
78 | }
79 |
80 | /**
81 | * Generates a new mock object for this container
82 | *
83 | * I apologies in advance for this. A God Method just fits the API which
84 | * doesn't require differentiating between classes, interfaces, abstracts,
85 | * names or partials - just so long as it's something that can be mocked.
86 | * I'll refactor it one day so it's easier to follow.
87 | *
88 | * @return \Mockery\Mock
89 | */
90 | public function mock()
91 | {
92 | $expectationClosure = null;
93 | $quickdefs = array();
94 | $constructorArgs = null;
95 | $blocks = array();
96 | $args = func_get_args();
97 |
98 | if (count($args) > 1) {
99 | $finalArg = end($args);
100 | reset($args);
101 | if (is_callable($finalArg) && is_object($finalArg)) {
102 | $expectationClosure = array_pop($args);
103 | }
104 | }
105 |
106 | $builder = new MockConfigurationBuilder();
107 |
108 | foreach ($args as $k => $arg) {
109 | if ($arg instanceof MockConfigurationBuilder) {
110 | $builder = $arg;
111 | unset($args[$k]);
112 | }
113 | }
114 | reset($args);
115 |
116 | $builder->setParameterOverrides(\Mockery::getConfiguration()->getInternalClassMethodParamMaps());
117 |
118 | while (count($args) > 0) {
119 | $arg = current($args);
120 | // check for multiple interfaces
121 | if (is_string($arg) && strpos($arg, ',') && !strpos($arg, ']')) {
122 | $interfaces = explode(',', str_replace(' ', '', $arg));
123 | foreach ($interfaces as $i) {
124 | if (!interface_exists($i, true) && !class_exists($i, true)) {
125 | throw new \Mockery\Exception(
126 | 'Class name follows the format for defining multiple'
127 | . ' interfaces, however one or more of the interfaces'
128 | . ' do not exist or are not included, or the base class'
129 | . ' (which you may omit from the mock definition) does not exist'
130 | );
131 | }
132 | }
133 | $builder->addTargets($interfaces);
134 | array_shift($args);
135 |
136 | continue;
137 | } elseif (is_string($arg) && substr($arg, 0, 6) == 'alias:') {
138 | $name = array_shift($args);
139 | $name = str_replace('alias:', '', $name);
140 | $builder->addTarget('stdClass');
141 | $builder->setName($name);
142 | continue;
143 | } elseif (is_string($arg) && substr($arg, 0, 9) == 'overload:') {
144 | $name = array_shift($args);
145 | $name = str_replace('overload:', '', $name);
146 | $builder->setInstanceMock(true);
147 | $builder->addTarget('stdClass');
148 | $builder->setName($name);
149 | continue;
150 | } elseif (is_string($arg) && substr($arg, strlen($arg)-1, 1) == ']') {
151 | $parts = explode('[', $arg);
152 | if (!class_exists($parts[0], true) && !interface_exists($parts[0], true)) {
153 | throw new \Mockery\Exception('Can only create a partial mock from'
154 | . ' an existing class or interface');
155 | }
156 | $class = $parts[0];
157 | $parts[1] = str_replace(' ','', $parts[1]);
158 | $partialMethods = explode(',', strtolower(rtrim($parts[1], ']')));
159 | $builder->addTarget($class);
160 | $builder->setWhiteListedMethods($partialMethods);
161 | array_shift($args);
162 | continue;
163 | } elseif (is_string($arg) && (class_exists($arg, true) || interface_exists($arg, true))) {
164 | $class = array_shift($args);
165 | $builder->addTarget($class);
166 | continue;
167 | } elseif (is_string($arg)) {
168 | $class = array_shift($args);
169 | $builder->addTarget($class);
170 | continue;
171 | } elseif (is_object($arg)) {
172 | $partial = array_shift($args);
173 | $builder->addTarget($partial);
174 | continue;
175 | } elseif (is_array($arg) && !empty($arg) && array_keys($arg) !== range(0, count($arg) - 1)) {
176 | // if associative array
177 | if(array_key_exists(self::BLOCKS, $arg)) $blocks = $arg[self::BLOCKS]; unset($arg[self::BLOCKS]);
178 | $quickdefs = array_shift($args);
179 | continue;
180 | } elseif (is_array($arg)) {
181 | $constructorArgs = array_shift($args);
182 | continue;
183 | }
184 |
185 | throw new \Mockery\Exception(
186 | 'Unable to parse arguments sent to '
187 | . get_class($this) . '::mock()'
188 | );
189 | }
190 |
191 | $builder->addBlackListedMethods($blocks);
192 |
193 | if (!is_null($constructorArgs)) {
194 | $builder->addBlackListedMethod("__construct"); // we need to pass through
195 | }
196 |
197 | if (!empty($partialMethods) && $constructorArgs === null) {
198 | $constructorArgs = array();
199 | }
200 |
201 | $config = $builder->getMockConfiguration();
202 |
203 | $this->checkForNamedMockClashes($config);
204 |
205 | $def = $this->getGenerator()->generate($config);
206 |
207 | if (class_exists($def->getClassName(), $attemptAutoload = false)) {
208 | $rfc = new \ReflectionClass($def->getClassName());
209 | if (!$rfc->implementsInterface("Mockery\MockInterface")) {
210 | throw new \Mockery\Exception\RuntimeException("Could not load mock {$def->getClassName()}, class already exists");
211 | }
212 | }
213 |
214 | $this->getLoader()->load($def);
215 |
216 | $mock = $this->_getInstance($def->getClassName(), $constructorArgs);
217 | $mock->mockery_init($this, $config->getTargetObject());
218 |
219 | if (!empty($quickdefs)) {
220 | $mock->shouldReceive($quickdefs)->byDefault();
221 | }
222 | if (!empty($expectationClosure)) {
223 | $expectationClosure($mock);
224 | }
225 | $this->rememberMock($mock);
226 | return $mock;
227 | }
228 |
229 | public function instanceMock()
230 | {
231 |
232 | }
233 |
234 | public function getLoader()
235 | {
236 | return $this->_loader;
237 | }
238 |
239 | public function getGenerator()
240 | {
241 | return $this->_generator;
242 | }
243 |
244 | /**
245 | * Tear down tasks for this container
246 | *
247 | * @return void
248 | */
249 | public function mockery_teardown()
250 | {
251 | try {
252 | $this->mockery_verify();
253 | } catch (\Exception $e) {
254 | $this->mockery_close();
255 | throw $e;
256 | }
257 | }
258 |
259 | /**
260 | * Verify the container mocks
261 | *
262 | * @return void
263 | */
264 | public function mockery_verify()
265 | {
266 | foreach($this->_mocks as $mock) {
267 | $mock->mockery_verify();
268 | }
269 | }
270 |
271 | /**
272 | * Reset the container to its original state
273 | *
274 | * @return void
275 | */
276 | public function mockery_close()
277 | {
278 | foreach($this->_mocks as $mock) {
279 | $mock->mockery_teardown();
280 | }
281 | $this->_mocks = array();
282 | }
283 |
284 | /**
285 | * Fetch the next available allocation order number
286 | *
287 | * @return int
288 | */
289 | public function mockery_allocateOrder()
290 | {
291 | $this->_allocatedOrder += 1;
292 | return $this->_allocatedOrder;
293 | }
294 |
295 | /**
296 | * Set ordering for a group
297 | *
298 | * @param mixed $group
299 | * @param int $order
300 | */
301 | public function mockery_setGroup($group, $order)
302 | {
303 | $this->_groups[$group] = $order;
304 | }
305 |
306 | /**
307 | * Fetch array of ordered groups
308 | *
309 | * @return array
310 | */
311 | public function mockery_getGroups()
312 | {
313 | return $this->_groups;
314 | }
315 |
316 | /**
317 | * Set current ordered number
318 | *
319 | * @param int $order
320 | * @return int The current order number that was set
321 | */
322 | public function mockery_setCurrentOrder($order)
323 | {
324 | $this->_currentOrder = $order;
325 | return $this->_currentOrder;
326 | }
327 |
328 | /**
329 | * Get current ordered number
330 | *
331 | * @return int
332 | */
333 | public function mockery_getCurrentOrder()
334 | {
335 | return $this->_currentOrder;
336 | }
337 |
338 | /**
339 | * Validate the current mock's ordering
340 | *
341 | * @param string $method
342 | * @param int $order
343 | * @throws \Mockery\Exception
344 | * @return void
345 | */
346 | public function mockery_validateOrder($method, $order, \Mockery\MockInterface $mock)
347 | {
348 | if ($order < $this->_currentOrder) {
349 | $exception = new \Mockery\Exception\InvalidOrderException(
350 | 'Method ' . $method . ' called out of order: expected order '
351 | . $order . ', was ' . $this->_currentOrder
352 | );
353 | $exception->setMock($mock)
354 | ->setMethodName($method)
355 | ->setExpectedOrder($order)
356 | ->setActualOrder($this->_currentOrder);
357 | throw $exception;
358 | }
359 | $this->mockery_setCurrentOrder($order);
360 | }
361 |
362 | /**
363 | * Gets the count of expectations on the mocks
364 | *
365 | * @return int
366 | */
367 | public function mockery_getExpectationCount()
368 | {
369 | $count = 0;
370 | foreach($this->_mocks as $mock) {
371 | $count += $mock->mockery_getExpectationCount();
372 | }
373 | return $count;
374 | }
375 |
376 | /**
377 | * Store a mock and set its container reference
378 | *
379 | * @param \Mockery\Mock
380 | * @return \Mockery\Mock
381 | */
382 | public function rememberMock(\Mockery\MockInterface $mock)
383 | {
384 | if (!isset($this->_mocks[get_class($mock)])) {
385 | $this->_mocks[get_class($mock)] = $mock;
386 | } else {
387 | /**
388 | * This condition triggers for an instance mock where origin mock
389 | * is already remembered
390 | */
391 | $this->_mocks[] = $mock;
392 | }
393 | return $mock;
394 | }
395 |
396 | /**
397 | * Retrieve the last remembered mock object, which is the same as saying
398 | * retrieve the current mock being programmed where you have yet to call
399 | * mock() to change it - thus why the method name is "self" since it will be
400 | * be used during the programming of the same mock.
401 | *
402 | * @return \Mockery\Mock
403 | */
404 | public function self()
405 | {
406 | $mocks = array_values($this->_mocks);
407 | $index = count($mocks) - 1;
408 | return $mocks[$index];
409 | }
410 |
411 | /**
412 | * Return a specific remembered mock according to the array index it
413 | * was stored to in this container instance
414 | *
415 | * @return \Mockery\Mock
416 | */
417 | public function fetchMock($reference)
418 | {
419 | if (isset($this->_mocks[$reference])) return $this->_mocks[$reference];
420 | }
421 |
422 | protected function _getInstance($mockName, $constructorArgs = null)
423 | {
424 | $r = new \ReflectionClass($mockName);
425 |
426 | if (null === $r->getConstructor()) {
427 | $return = new $mockName;
428 | return $return;
429 | }
430 |
431 | if ($constructorArgs !== null) {
432 | return $r->newInstanceArgs($constructorArgs);
433 | }
434 |
435 | $return = unserialize(sprintf('O:%d:"%s":0:{}', strlen($mockName), $mockName));
436 | return $return;
437 | }
438 |
439 | /**
440 | * Takes a class name and declares it
441 | *
442 | * @param string $fqcn
443 | */
444 | public function declareClass($fqcn)
445 | {
446 | if (false !== strpos($fqcn, '/')) {
447 | throw new \Mockery\Exception(
448 | 'Class name contains a forward slash instead of backslash needed '
449 | . 'when employing namespaces'
450 | );
451 | }
452 | if (false !== strpos($fqcn, "\\")) {
453 | $parts = array_filter(explode("\\", $fqcn), function ($part) {
454 | return $part !== "";
455 | });
456 | $cl = array_pop($parts);
457 | $ns = implode("\\", $parts);
458 | eval(" namespace $ns { class $cl {} }");
459 | } else {
460 | eval(" class $fqcn {} ");
461 | }
462 | }
463 |
464 | protected function checkForNamedMockClashes($config)
465 | {
466 | $name = $config->getName();
467 |
468 | if (!$name) {
469 | return;
470 | }
471 |
472 | $hash = $config->getHash();
473 |
474 | if (isset($this->_namedMocks[$name])) {
475 | if ($hash !== $this->_namedMocks[$name]) {
476 | throw new \Mockery\Exception(
477 | "The mock named '$name' has been already defined with a different mock configuration"
478 | );
479 | }
480 | }
481 |
482 | $this->_namedMocks[$name] = $hash;
483 | }
484 | }