This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 [email protected] so we can send you a copy immediately. |
||
14 | * |
||
15 | * @category Mockery |
||
16 | * @package Mockery |
||
17 | * @copyright Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com) |
||
18 | * @license http://github.com/padraic/mockery/blob/master/LICENSE New BSD License |
||
19 | */ |
||
20 | |||
21 | use Mockery\ExpectationInterface; |
||
22 | use Mockery\Generator\CachingGenerator; |
||
23 | use Mockery\Generator\Generator; |
||
0 ignored issues
–
show
|
|||
24 | use Mockery\Generator\MockConfigurationBuilder; |
||
25 | use Mockery\Generator\StringManipulationGenerator; |
||
26 | use Mockery\Loader\EvalLoader; |
||
27 | use Mockery\Loader\Loader; |
||
28 | use Mockery\Matcher\MatcherAbstract; |
||
29 | |||
30 | class Mockery |
||
31 | { |
||
32 | const BLOCKS = 'Mockery_Forward_Blocks'; |
||
33 | |||
34 | /** |
||
35 | * Global container to hold all mocks for the current unit test running. |
||
36 | * |
||
37 | * @var \Mockery\Container |
||
38 | */ |
||
39 | protected static $_container = null; |
||
40 | |||
41 | /** |
||
42 | * Global configuration handler containing configuration options. |
||
43 | * |
||
44 | * @var \Mockery\Configuration |
||
45 | */ |
||
46 | protected static $_config = null; |
||
47 | |||
48 | /** |
||
49 | * @var \Mockery\Generator\Generator |
||
50 | */ |
||
51 | protected static $_generator; |
||
52 | |||
53 | /** |
||
54 | * @var \Mockery\Loader\Loader |
||
55 | */ |
||
56 | protected static $_loader; |
||
57 | |||
58 | /** |
||
59 | * @var array |
||
60 | */ |
||
61 | private static $_filesToCleanUp = []; |
||
62 | |||
63 | /** |
||
64 | * Defines the global helper functions |
||
65 | * |
||
66 | * @return void |
||
67 | */ |
||
68 | 3 | public static function globalHelpers() |
|
69 | { |
||
70 | 3 | require_once __DIR__.'/helpers.php'; |
|
71 | 3 | } |
|
72 | |||
73 | /** |
||
74 | * Static shortcut to \Mockery\Container::mock(). |
||
75 | * |
||
76 | * @param array $args |
||
77 | * |
||
78 | * @return \Mockery\MockInterface |
||
79 | */ |
||
80 | 38 | public static function mock(...$args) |
|
81 | { |
||
82 | 38 | return call_user_func_array(array(self::getContainer(), 'mock'), $args); |
|
83 | } |
||
84 | |||
85 | /** |
||
86 | * Static and semantic shortcut for getting a mock from the container |
||
87 | * and applying the spy's expected behavior into it. |
||
88 | * |
||
89 | * @param array $args |
||
90 | * |
||
91 | * @return \Mockery\MockInterface |
||
92 | */ |
||
93 | 9 | public static function spy(...$args) |
|
94 | { |
||
95 | 9 | return call_user_func_array(array(self::getContainer(), 'mock'), $args)->shouldIgnoreMissing(); |
|
96 | } |
||
97 | |||
98 | /** |
||
99 | * Static and Semantic shortcut to \Mockery\Container::mock(). |
||
100 | * |
||
101 | * @param array $args |
||
102 | * |
||
103 | * @return \Mockery\MockInterface |
||
104 | */ |
||
105 | public static function instanceMock(...$args) |
||
106 | { |
||
107 | return call_user_func_array(array(self::getContainer(), 'mock'), $args); |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * Static shortcut to \Mockery\Container::mock(), first argument names the mock. |
||
112 | * |
||
113 | * @param array $args |
||
114 | * |
||
115 | * @return \Mockery\MockInterface |
||
116 | */ |
||
117 | 5 | public static function namedMock(...$args) |
|
118 | { |
||
119 | 5 | $name = array_shift($args); |
|
120 | |||
121 | 5 | $builder = new MockConfigurationBuilder(); |
|
122 | 5 | $builder->setName($name); |
|
123 | |||
124 | 5 | array_unshift($args, $builder); |
|
125 | |||
126 | 5 | return call_user_func_array(array(self::getContainer(), 'mock'), $args); |
|
127 | } |
||
128 | |||
129 | /** |
||
130 | * Static shortcut to \Mockery\Container::self(). |
||
131 | * |
||
132 | * @throws LogicException |
||
133 | * |
||
134 | * @return \Mockery\MockInterface |
||
135 | */ |
||
136 | 2 | public static function self() |
|
137 | { |
||
138 | 2 | if (is_null(self::$_container)) { |
|
139 | 1 | throw new \LogicException('You have not declared any mocks yet'); |
|
140 | } |
||
141 | |||
142 | 1 | return self::$_container->self(); |
|
143 | } |
||
144 | |||
145 | /** |
||
146 | * Static shortcut to closing up and verifying all mocks in the global |
||
147 | * container, and resetting the container static variable to null. |
||
148 | * |
||
149 | * @return void |
||
150 | */ |
||
151 | 414 | public static function close() |
|
152 | { |
||
153 | 414 | foreach (self::$_filesToCleanUp as $fileName) { |
|
154 | 18 | @unlink($fileName); |
|
155 | 414 | } |
|
156 | 414 | self::$_filesToCleanUp = []; |
|
157 | |||
158 | 414 | if (is_null(self::$_container)) { |
|
159 | return; |
||
160 | } |
||
161 | |||
162 | 414 | self::$_container->mockery_teardown(); |
|
163 | 412 | self::$_container->mockery_close(); |
|
164 | 412 | self::$_container = null; |
|
165 | 412 | } |
|
166 | |||
167 | /** |
||
168 | * Static fetching of a mock associated with a name or explicit class poser. |
||
169 | * |
||
170 | * @param $name |
||
171 | * |
||
172 | * @return \Mockery\Mock |
||
173 | */ |
||
174 | 11 | public static function fetchMock($name) |
|
175 | { |
||
176 | 11 | return self::$_container->fetchMock($name); |
|
177 | } |
||
178 | |||
179 | /** |
||
180 | * Lazy loader and getter for |
||
181 | * the container property. |
||
182 | * |
||
183 | * @return Mockery\Container |
||
184 | */ |
||
185 | 438 | public static function getContainer() |
|
186 | { |
||
187 | 438 | if (is_null(self::$_container)) { |
|
188 | 407 | self::$_container = new Mockery\Container(self::getGenerator(), self::getLoader()); |
|
189 | 407 | } |
|
190 | |||
191 | 438 | return self::$_container; |
|
192 | } |
||
193 | |||
194 | /** |
||
195 | * Setter for the $_generator static propery. |
||
196 | * |
||
197 | * @param \Mockery\Generator\Generator $generator |
||
198 | */ |
||
199 | public static function setGenerator(Generator $generator) |
||
200 | { |
||
201 | self::$_generator = $generator; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Lazy loader method and getter for |
||
206 | * the generator property. |
||
207 | * |
||
208 | * @return Generator |
||
209 | */ |
||
210 | 407 | public static function getGenerator() |
|
211 | { |
||
212 | 407 | if (is_null(self::$_generator)) { |
|
213 | 1 | self::$_generator = self::getDefaultGenerator(); |
|
214 | 1 | } |
|
215 | |||
216 | 407 | return self::$_generator; |
|
217 | } |
||
218 | |||
219 | /** |
||
220 | * Creates and returns a default generator |
||
221 | * used inside this class. |
||
222 | * |
||
223 | * @return CachingGenerator |
||
224 | */ |
||
225 | 400 | public static function getDefaultGenerator() |
|
226 | { |
||
227 | 400 | return new CachingGenerator(StringManipulationGenerator::withDefaultPasses()); |
|
228 | } |
||
229 | |||
230 | /** |
||
231 | * Setter for the $_loader static property. |
||
232 | * |
||
233 | * @param Loader $loader |
||
234 | */ |
||
235 | public static function setLoader(Loader $loader) |
||
236 | { |
||
237 | self::$_loader = $loader; |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | * Lazy loader method and getter for |
||
242 | * the $_loader property. |
||
243 | * |
||
244 | * @return Loader |
||
245 | */ |
||
246 | 407 | public static function getLoader() |
|
247 | { |
||
248 | 407 | if (is_null(self::$_loader)) { |
|
249 | 1 | self::$_loader = self::getDefaultLoader(); |
|
250 | 1 | } |
|
251 | |||
252 | 407 | return self::$_loader; |
|
253 | } |
||
254 | |||
255 | /** |
||
256 | * Gets an EvalLoader to be used as default. |
||
257 | * |
||
258 | * @return EvalLoader |
||
259 | */ |
||
260 | 274 | public static function getDefaultLoader() |
|
261 | { |
||
262 | 274 | return new EvalLoader(); |
|
263 | } |
||
264 | |||
265 | /** |
||
266 | * Set the container. |
||
267 | * |
||
268 | * @param \Mockery\Container $container |
||
269 | * |
||
270 | * @return \Mockery\Container |
||
271 | */ |
||
272 | 18 | public static function setContainer(Mockery\Container $container) |
|
273 | { |
||
274 | 18 | return self::$_container = $container; |
|
275 | } |
||
276 | |||
277 | /** |
||
278 | * Reset the container to null. |
||
279 | * |
||
280 | * @return void |
||
281 | */ |
||
282 | 15 | public static function resetContainer() |
|
283 | { |
||
284 | 15 | self::$_container = null; |
|
285 | 15 | } |
|
286 | |||
287 | /** |
||
288 | * Return instance of ANY matcher. |
||
289 | * |
||
290 | * @return \Mockery\Matcher\Any |
||
291 | */ |
||
292 | 5 | public static function any() |
|
293 | { |
||
294 | 5 | return new \Mockery\Matcher\Any(); |
|
295 | } |
||
296 | |||
297 | /** |
||
298 | * Return instance of TYPE matcher. |
||
299 | * |
||
300 | * @param $expected |
||
301 | * |
||
302 | * @return \Mockery\Matcher\Type |
||
303 | */ |
||
304 | 48 | public static function type($expected) |
|
305 | { |
||
306 | 48 | return new \Mockery\Matcher\Type($expected); |
|
307 | } |
||
308 | |||
309 | /** |
||
310 | * Return instance of DUCKTYPE matcher. |
||
311 | * |
||
312 | * @param array $args |
||
313 | * |
||
314 | * @return \Mockery\Matcher\Ducktype |
||
315 | */ |
||
316 | 3 | public static function ducktype(...$args) |
|
317 | { |
||
318 | 3 | return new \Mockery\Matcher\Ducktype($args); |
|
319 | } |
||
320 | |||
321 | /** |
||
322 | * Return instance of SUBSET matcher. |
||
323 | * |
||
324 | * @param array $part |
||
325 | * @param bool $strict - (Optional) True for strict comparison, false for loose |
||
326 | * |
||
327 | * @return \Mockery\Matcher\Subset |
||
328 | */ |
||
329 | 3 | public static function subset(array $part, $strict = true) |
|
330 | { |
||
331 | 3 | return new \Mockery\Matcher\Subset($part, $strict); |
|
332 | } |
||
333 | |||
334 | /** |
||
335 | * Return instance of CONTAINS matcher. |
||
336 | * |
||
337 | * @param array $args |
||
338 | * |
||
339 | * @return \Mockery\Matcher\Contains |
||
340 | */ |
||
341 | 3 | public static function contains(...$args) |
|
342 | { |
||
343 | 3 | return new \Mockery\Matcher\Contains($args); |
|
344 | } |
||
345 | |||
346 | /** |
||
347 | * Return instance of HASKEY matcher. |
||
348 | * |
||
349 | * @param $key |
||
350 | * |
||
351 | * @return \Mockery\Matcher\HasKey |
||
352 | */ |
||
353 | 4 | public static function hasKey($key) |
|
354 | { |
||
355 | 4 | return new \Mockery\Matcher\HasKey($key); |
|
356 | } |
||
357 | |||
358 | /** |
||
359 | * Return instance of HASVALUE matcher. |
||
360 | * |
||
361 | * @param $val |
||
362 | * |
||
363 | * @return \Mockery\Matcher\HasValue |
||
364 | */ |
||
365 | 3 | public static function hasValue($val) |
|
366 | { |
||
367 | 3 | return new \Mockery\Matcher\HasValue($val); |
|
368 | } |
||
369 | |||
370 | /** |
||
371 | * Return instance of CLOSURE matcher. |
||
372 | * |
||
373 | * @param $closure |
||
374 | * |
||
375 | * @return \Mockery\Matcher\Closure |
||
376 | */ |
||
377 | 7 | public static function on($closure) |
|
378 | { |
||
379 | 7 | return new \Mockery\Matcher\Closure($closure); |
|
380 | } |
||
381 | |||
382 | /** |
||
383 | * Return instance of MUSTBE matcher. |
||
384 | * |
||
385 | * @param $expected |
||
386 | * |
||
387 | * @return \Mockery\Matcher\MustBe |
||
388 | */ |
||
389 | 6 | public static function mustBe($expected) |
|
390 | { |
||
391 | 6 | return new \Mockery\Matcher\MustBe($expected); |
|
0 ignored issues
–
show
The class
Mockery\Matcher\MustBe has been deprecated with message: 2.0 Due to ambiguity, use Hamcrest or PHPUnit equivalents
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead. ![]() |
|||
392 | } |
||
393 | |||
394 | /** |
||
395 | * Return instance of NOT matcher. |
||
396 | * |
||
397 | * @param $expected |
||
398 | * |
||
399 | * @return \Mockery\Matcher\Not |
||
400 | */ |
||
401 | 3 | public static function not($expected) |
|
402 | { |
||
403 | 3 | return new \Mockery\Matcher\Not($expected); |
|
404 | } |
||
405 | |||
406 | /** |
||
407 | * Return instance of ANYOF matcher. |
||
408 | * |
||
409 | * @param array $args |
||
410 | * |
||
411 | * @return \Mockery\Matcher\AnyOf |
||
412 | */ |
||
413 | 3 | public static function anyOf(...$args) |
|
414 | { |
||
415 | 3 | return new \Mockery\Matcher\AnyOf($args); |
|
416 | } |
||
417 | |||
418 | /** |
||
419 | * Return instance of NOTANYOF matcher. |
||
420 | * |
||
421 | * @param array $args |
||
422 | * |
||
423 | * @return \Mockery\Matcher\NotAnyOf |
||
424 | */ |
||
425 | 3 | public static function notAnyOf(...$args) |
|
426 | { |
||
427 | 3 | return new \Mockery\Matcher\NotAnyOf($args); |
|
428 | } |
||
429 | |||
430 | /** |
||
431 | * Lazy loader and Getter for the global |
||
432 | * configuration container. |
||
433 | * |
||
434 | * @return \Mockery\Configuration |
||
435 | */ |
||
436 | 426 | public static function getConfiguration() |
|
437 | { |
||
438 | 426 | if (is_null(self::$_config)) { |
|
439 | 1 | self::$_config = new \Mockery\Configuration(); |
|
440 | 1 | } |
|
441 | |||
442 | 426 | return self::$_config; |
|
443 | } |
||
444 | |||
445 | /** |
||
446 | * Utility method to format method name and arguments into a string. |
||
447 | * |
||
448 | * @param string $method |
||
449 | * @param array $arguments |
||
450 | * |
||
451 | * @return string |
||
452 | */ |
||
453 | 93 | public static function formatArgs($method, array $arguments = null) |
|
454 | { |
||
455 | 93 | if (is_null($arguments)) { |
|
456 | return $method . '()'; |
||
457 | } |
||
458 | |||
459 | 93 | $formattedArguments = array(); |
|
460 | 93 | foreach ($arguments as $argument) { |
|
461 | 92 | $formattedArguments[] = self::formatArgument($argument); |
|
462 | 93 | } |
|
463 | |||
464 | 93 | return $method . '(' . implode(', ', $formattedArguments) . ')'; |
|
465 | } |
||
466 | |||
467 | /** |
||
468 | * Gets the string representation |
||
469 | * of any passed argument. |
||
470 | * |
||
471 | * @param $argument |
||
472 | * @param $depth |
||
473 | * |
||
474 | * @return string |
||
475 | */ |
||
476 | 92 | private static function formatArgument($argument, $depth = 0) |
|
477 | { |
||
478 | 92 | if ($argument instanceOf MatcherAbstract) { |
|
479 | 35 | return (string) $argument; |
|
480 | } |
||
481 | |||
482 | 57 | if (is_object($argument)) { |
|
483 | 7 | return 'object(' . get_class($argument) . ')'; |
|
484 | } |
||
485 | |||
486 | 54 | if (is_int($argument) || is_float($argument)) { |
|
487 | 37 | return $argument; |
|
488 | } |
||
489 | |||
490 | 26 | if (is_array($argument)) { |
|
491 | 13 | if ($depth === 1) { |
|
492 | 2 | $argument = '[...]'; |
|
493 | 2 | } else { |
|
494 | 13 | $sample = array(); |
|
495 | 13 | foreach ($argument as $key => $value) { |
|
496 | 12 | $key = is_int($key) ? $key : "'$key'"; |
|
497 | 12 | $value = self::formatArgument($value, $depth + 1); |
|
498 | 12 | $sample[] = "$key => $value"; |
|
499 | 13 | } |
|
500 | |||
501 | 13 | $argument = "[".implode(", ", $sample)."]"; |
|
502 | } |
||
503 | |||
504 | 13 | return ((strlen($argument) > 1000) ? substr($argument, 0, 1000).'...]' : $argument); |
|
505 | } |
||
506 | |||
507 | 17 | if (is_bool($argument)) { |
|
508 | 1 | return $argument ? 'true' : 'false'; |
|
509 | } |
||
510 | |||
511 | 16 | if (is_resource($argument)) { |
|
512 | 2 | return 'resource(...)'; |
|
513 | } |
||
514 | |||
515 | 14 | if (is_null($argument)) { |
|
516 | 1 | return 'NULL'; |
|
517 | } |
||
518 | |||
519 | 13 | return "'".(string) $argument."'"; |
|
520 | } |
||
521 | |||
522 | /** |
||
523 | * Utility function to format objects to printable arrays. |
||
524 | * |
||
525 | * @param array $objects |
||
526 | * |
||
527 | * @return string |
||
528 | */ |
||
529 | 52 | public static function formatObjects(array $objects = null) |
|
530 | { |
||
531 | 52 | static $formatting; |
|
532 | |||
533 | 52 | if ($formatting) { |
|
534 | 1 | return '[Recursion]'; |
|
535 | } |
||
536 | |||
537 | 52 | if (is_null($objects)) { |
|
538 | return ''; |
||
539 | } |
||
540 | |||
541 | 52 | $objects = array_filter($objects, 'is_object'); |
|
542 | 52 | if (empty($objects)) { |
|
543 | 45 | return ''; |
|
544 | } |
||
545 | |||
546 | 7 | $formatting = true; |
|
547 | 7 | $parts = array(); |
|
548 | |||
549 | 7 | foreach ($objects as $object) { |
|
550 | 7 | $parts[get_class($object)] = self::objectToArray($object); |
|
551 | 7 | } |
|
552 | |||
553 | 7 | $formatting = false; |
|
554 | |||
555 | 7 | return 'Objects: ( ' . var_export($parts, true) . ')'; |
|
556 | } |
||
557 | |||
558 | /** |
||
559 | * Utility function to turn public properties and public get* and is* method values into an array. |
||
560 | * |
||
561 | * @param $object |
||
562 | * @param int $nesting |
||
563 | * |
||
564 | * @return array |
||
565 | */ |
||
566 | 7 | private static function objectToArray($object, $nesting = 3) |
|
567 | { |
||
568 | 7 | if ($nesting == 0) { |
|
569 | return array('...'); |
||
570 | } |
||
571 | |||
572 | return array( |
||
573 | 7 | 'class' => get_class($object), |
|
574 | 7 | 'properties' => self::extractInstancePublicProperties($object, $nesting), |
|
575 | 7 | 'getters' => self::extractGetters($object, $nesting) |
|
576 | 7 | ); |
|
577 | } |
||
578 | |||
579 | /** |
||
580 | * Returns all public instance properties. |
||
581 | * |
||
582 | * @param $object |
||
583 | * @param $nesting |
||
584 | * |
||
585 | * @return array |
||
586 | */ |
||
587 | 7 | private static function extractInstancePublicProperties($object, $nesting) |
|
588 | { |
||
589 | 7 | $reflection = new \ReflectionClass(get_class($object)); |
|
590 | 7 | $properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC); |
|
591 | 7 | $cleanedProperties = array(); |
|
592 | |||
593 | 7 | foreach ($properties as $publicProperty) { |
|
594 | 1 | if (!$publicProperty->isStatic()) { |
|
595 | $name = $publicProperty->getName(); |
||
596 | $cleanedProperties[$name] = self::cleanupNesting($object->$name, $nesting); |
||
597 | } |
||
598 | 7 | } |
|
599 | |||
600 | 7 | return $cleanedProperties; |
|
601 | } |
||
602 | |||
603 | /** |
||
604 | * Returns all object getters. |
||
605 | * |
||
606 | * @param $object |
||
607 | * @param $nesting |
||
608 | * |
||
609 | * @return array |
||
610 | */ |
||
611 | 7 | private static function extractGetters($object, $nesting) |
|
612 | { |
||
613 | 7 | $reflection = new \ReflectionClass(get_class($object)); |
|
614 | 7 | $publicMethods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); |
|
615 | 7 | $getters = array(); |
|
616 | |||
617 | 7 | foreach ($publicMethods as $publicMethod) { |
|
618 | 5 | $name = $publicMethod->getName(); |
|
0 ignored issues
–
show
![]() |
|||
619 | 5 | $irrelevantName = (substr($name, 0, 3) !== 'get' && substr($name, 0, 2) !== 'is'); |
|
620 | 5 | $isStatic = $publicMethod->isStatic(); |
|
621 | 5 | $numberOfParameters = $publicMethod->getNumberOfParameters(); |
|
622 | |||
623 | 5 | if ($irrelevantName || $numberOfParameters != 0 || $isStatic) { |
|
624 | 5 | continue; |
|
625 | } |
||
626 | |||
627 | try { |
||
628 | 2 | $getters[$name] = self::cleanupNesting($object->$name(), $nesting); |
|
629 | 2 | } catch (\Exception $e) { |
|
630 | 1 | $getters[$name] = '!! ' . get_class($e) . ': ' . $e->getMessage() . ' !!'; |
|
631 | } |
||
632 | 7 | } |
|
633 | |||
634 | 7 | return $getters; |
|
635 | } |
||
636 | |||
637 | /** |
||
638 | * Utility method used for recursively generating |
||
639 | * an object or array representation. |
||
640 | * |
||
641 | * @param $argument |
||
642 | * @param $nesting |
||
643 | * |
||
644 | * @return mixed |
||
645 | */ |
||
646 | 1 | private static function cleanupNesting($argument, $nesting) |
|
647 | { |
||
648 | 1 | if (is_object($argument)) { |
|
649 | $object = self::objectToArray($argument, $nesting - 1); |
||
650 | $object['class'] = get_class($argument); |
||
651 | |||
652 | return $object; |
||
653 | } |
||
654 | |||
655 | 1 | if (is_array($argument)) { |
|
656 | 1 | return self::cleanupArray($argument, $nesting - 1); |
|
657 | } |
||
658 | |||
659 | 1 | return $argument; |
|
660 | } |
||
661 | |||
662 | /** |
||
663 | * Utility method for recursively |
||
664 | * gerating a representation |
||
665 | * of the given array. |
||
666 | * |
||
667 | * @param array $argument |
||
668 | * @param int $nesting |
||
669 | * |
||
670 | * @return mixed |
||
671 | */ |
||
672 | 1 | private static function cleanupArray($argument, $nesting = 3) |
|
673 | { |
||
674 | 1 | if ($nesting == 0) { |
|
675 | 1 | return '...'; |
|
676 | } |
||
677 | |||
678 | 1 | foreach ($argument as $key => $value) { |
|
679 | 1 | if (is_array($value)) { |
|
680 | 1 | $argument[$key] = self::cleanupArray($value, $nesting - 1); |
|
681 | 1 | } elseif (is_object($value)) { |
|
682 | $argument[$key] = self::objectToArray($value, $nesting - 1); |
||
683 | } |
||
684 | 1 | } |
|
685 | |||
686 | 1 | return $argument; |
|
687 | } |
||
688 | |||
689 | /** |
||
690 | * Utility function to parse shouldReceive() arguments and generate |
||
691 | * expectations from such as needed. |
||
692 | * |
||
693 | * @param Mockery\MockInterface $mock |
||
694 | * @param array $args |
||
695 | * @param callable $add |
||
696 | * @return \Mockery\CompositeExpectation |
||
697 | */ |
||
698 | 308 | public static function parseShouldReturnArgs(\Mockery\MockInterface $mock, $args, $add) |
|
699 | { |
||
700 | 308 | $composite = new \Mockery\CompositeExpectation(); |
|
701 | |||
702 | 308 | foreach ($args as $arg) { |
|
703 | 308 | if (is_array($arg)) { |
|
704 | 18 | foreach ($arg as $k => $v) { |
|
705 | 18 | $expectation = self::buildDemeterChain($mock, $k, $add)->andReturn($v); |
|
0 ignored issues
–
show
The call to
ExpectationInterface::andReturn() has too many arguments starting with $v .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the ![]() |
|||
706 | 18 | $composite->add($expectation); |
|
0 ignored issues
–
show
$expectation is of type object<Mockery\ExpectationInterface> , but the function expects a object<Mockery\Expectati...y\CompositeExpectation> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
707 | 18 | } |
|
708 | 308 | } elseif (is_string($arg)) { |
|
709 | 294 | $expectation = self::buildDemeterChain($mock, $arg, $add); |
|
710 | 288 | $composite->add($expectation); |
|
0 ignored issues
–
show
$expectation is of type object<Mockery\ExpectationInterface> , but the function expects a object<Mockery\Expectati...y\CompositeExpectation> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
711 | 288 | } |
|
712 | 302 | } |
|
713 | |||
714 | 302 | return $composite; |
|
715 | } |
||
716 | |||
717 | /** |
||
718 | * Sets up expectations on the members of the CompositeExpectation and |
||
719 | * builds up any demeter chain that was passed to shouldReceive. |
||
720 | * |
||
721 | * @param \Mockery\MockInterface $mock |
||
722 | * @param string $arg |
||
723 | * @param callable $add |
||
724 | * @throws Mockery\Exception |
||
725 | * @return \Mockery\ExpectationInterface |
||
726 | */ |
||
727 | 308 | protected static function buildDemeterChain(\Mockery\MockInterface $mock, $arg, $add) |
|
728 | { |
||
729 | /** @var Mockery\Container $container */ |
||
730 | 308 | $container = $mock->mockery_getContainer(); |
|
731 | 308 | $methodNames = explode('->', $arg); |
|
732 | 308 | reset($methodNames); |
|
733 | |||
734 | 308 | if (!\Mockery::getConfiguration()->mockingNonExistentMethodsAllowed() |
|
735 | 308 | && !$mock->mockery_isAnonymous() |
|
736 | 308 | && !in_array(current($methodNames), $mock->mockery_getMockableMethods()) |
|
737 | 308 | ) { |
|
738 | 4 | throw new \Mockery\Exception( |
|
739 | 'Mockery\'s configuration currently forbids mocking the method ' |
||
740 | 4 | . current($methodNames) . ' as it does not exist on the class or object ' |
|
741 | 4 | . 'being mocked' |
|
742 | 4 | ); |
|
743 | } |
||
744 | |||
745 | /** @var ExpectationInterface|null $expectations */ |
||
746 | 304 | $expectations = null; |
|
747 | |||
748 | /** @var Callable $nextExp */ |
||
749 | $nextExp = function ($method) use ($add) { |
||
750 | 304 | return $add($method); |
|
751 | 304 | }; |
|
752 | |||
753 | 304 | while (true) { |
|
754 | 304 | $method = array_shift($methodNames); |
|
755 | 304 | $expectations = $mock->mockery_getExpectationsFor($method); |
|
756 | |||
757 | 304 | if (is_null($expectations) || self::noMoreElementsInChain($methodNames)) { |
|
758 | 304 | $expectations = $nextExp($method); |
|
759 | 302 | if (self::noMoreElementsInChain($methodNames)) { |
|
760 | 302 | break; |
|
761 | } |
||
762 | |||
763 | 11 | $mock = self::getNewDemeterMock($container, $method, $expectations); |
|
764 | 11 | } else { |
|
765 | 5 | $demeterMockKey = $container->getKeyOfDemeterMockFor($method); |
|
766 | 5 | if ($demeterMockKey) { |
|
767 | 5 | $mock = self::getExistingDemeterMock($container, $demeterMockKey); |
|
768 | 5 | } |
|
769 | } |
||
770 | |||
771 | 11 | $nextExp = function ($n) use ($mock) { |
|
772 | 11 | return $mock->shouldReceive($n); |
|
773 | 11 | }; |
|
774 | 11 | } |
|
775 | |||
776 | 302 | return $expectations; |
|
777 | } |
||
778 | |||
779 | /** |
||
780 | * Gets a new demeter configured |
||
781 | * mock from the container. |
||
782 | * |
||
783 | * @param \Mockery\Container $container |
||
784 | * @param string $method |
||
785 | * @param Mockery\ExpectationInterface $exp |
||
786 | * |
||
787 | * @return \Mockery\Mock |
||
788 | */ |
||
789 | 11 | private static function getNewDemeterMock( |
|
790 | Mockery\Container $container, |
||
791 | $method, |
||
792 | Mockery\ExpectationInterface $exp |
||
793 | ) { |
||
794 | 11 | $mock = $container->mock('demeter_' . $method); |
|
795 | 11 | $exp->andReturn($mock); |
|
796 | |||
797 | 11 | return $mock; |
|
798 | } |
||
799 | |||
800 | /** |
||
801 | * Gets an specific demeter mock from |
||
802 | * the ones kept by the container. |
||
803 | * |
||
804 | * @param \Mockery\Container $container |
||
805 | * @param string $demeterMockKey |
||
806 | * |
||
807 | * @return mixed |
||
808 | */ |
||
809 | 5 | private static function getExistingDemeterMock( |
|
810 | Mockery\Container $container, |
||
811 | $demeterMockKey |
||
812 | ) { |
||
813 | 5 | $mocks = $container->getMocks(); |
|
814 | 5 | $mock = $mocks[$demeterMockKey]; |
|
815 | |||
816 | 5 | return $mock; |
|
817 | } |
||
818 | |||
819 | /** |
||
820 | * Checks if the passed array representing a demeter |
||
821 | * chain with the method names is empty. |
||
822 | * |
||
823 | * @param array $methodNames |
||
824 | * |
||
825 | * @return bool |
||
826 | */ |
||
827 | 302 | private static function noMoreElementsInChain(array $methodNames) |
|
828 | { |
||
829 | 302 | return empty($methodNames); |
|
830 | } |
||
831 | |||
832 | 17 | public static function declareClass($fqn) |
|
833 | { |
||
834 | 17 | return static::declareType($fqn, "class"); |
|
0 ignored issues
–
show
Since
declareType() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self , or increase the visibility of declareType() to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return static::getTemperature();
}
} The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass {
private static function getTemperature() {
return "-182 °C";
}
}
print YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return self::getTemperature();
}
}
![]() |
|||
835 | } |
||
836 | |||
837 | 2 | public static function declareInterface($fqn) |
|
838 | { |
||
839 | 2 | return static::declareType($fqn, "interface"); |
|
0 ignored issues
–
show
Since
declareType() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self , or increase the visibility of declareType() to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return static::getTemperature();
}
} The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass {
private static function getTemperature() {
return "-182 °C";
}
}
print YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return self::getTemperature();
}
}
![]() |
|||
840 | } |
||
841 | |||
842 | 18 | private static function declareType($fqn, $type) |
|
843 | { |
||
844 | 18 | $targetCode = "<?php "; |
|
845 | 18 | $shortName = $fqn; |
|
846 | |||
847 | 18 | if (strpos($fqn, "\\")) { |
|
848 | 4 | $parts = explode("\\", $fqn); |
|
849 | |||
850 | 4 | $shortName = trim(array_pop($parts)); |
|
851 | 4 | $namespace = implode("\\", $parts); |
|
852 | |||
853 | 4 | $targetCode.= "namespace $namespace;\n"; |
|
854 | 4 | } |
|
855 | |||
856 | 18 | $targetCode.= "$type $shortName {} "; |
|
857 | |||
858 | /* |
||
859 | * We could eval here, but it doesn't play well with the way |
||
860 | * PHPUnit tries to backup global state and the require definition |
||
861 | * loader |
||
862 | */ |
||
863 | 18 | $tmpfname = tempnam(sys_get_temp_dir(), "Mockery"); |
|
864 | 18 | file_put_contents($tmpfname, $targetCode); |
|
865 | 18 | require $tmpfname; |
|
866 | 18 | \Mockery::registerFileForCleanUp($tmpfname); |
|
867 | 18 | } |
|
868 | |||
869 | /** |
||
870 | * Register a file to be deleted on tearDown. |
||
871 | * |
||
872 | * @param string $fileName |
||
873 | */ |
||
874 | 18 | public static function registerFileForCleanUp($fileName) |
|
875 | { |
||
876 | 18 | self::$_filesToCleanUp[] = $fileName; |
|
877 | 18 | } |
|
878 | } |
||
879 |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: