Completed
Push — master ( 7ee214...32fd8d )
by Alberto
19s
created

Moka::getCurrentTestCase()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 4
nop 0
dl 0
loc 22
ccs 8
cts 8
cp 1
crap 4
rs 8.9197
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Moka;
5
6
use Mockery\MockInterface;
7
use Moka\Exception\InvalidIdentifierException;
8
use Moka\Exception\MissingDependencyException;
9
use Moka\Exception\MockNotCreatedException;
10
use Moka\Exception\NotImplementedException;
11
use Moka\Factory\ProxyBuilderFactory;
12
use Moka\Plugin\PluginHelper;
13
use Moka\Proxy\ProxyInterface;
14
use Moka\Proxy\ProxyTrait;
15
use Moka\Strategy\MockingStrategyInterface;
16
use Phake_IMock as PhakeMock;
17
use PHPUnit\Framework\TestCase;
18
use PHPUnit_Framework_MockObject_MockObject as MockObject;
19
use Prophecy\Prophecy\ObjectProphecy;
20
use Prophecy\Prophet;
21
22
/**
23
 * Class Moka
24
 * @package Moka
25
 *
26
 * @method static MockInterface|ProxyInterface mockery(string $fqcnOrAlias, string $alias = null)
27
 * @method static PhakeMock|ProxyInterface phake(string $fqcnOrAlias, string $alias = null)
28
 */
29
class Moka
30
{
31
    /**
32
     * @var array|MockingStrategyInterface[]
33
     */
34
    private static $mockingStrategies = [];
35
36
    /**
37
     * @param string $name
38
     * @param array $arguments
39
     * @return ProxyInterface
40
     *
41
     * @throws NotImplementedException
42
     * @throws InvalidIdentifierException
43
     * @throws MockNotCreatedException
44
     * @throws MissingDependencyException
45
     */
46 5
    public static function __callStatic(string $name, array $arguments): ProxyInterface
47
    {
48 5
        if (!isset(self::$mockingStrategies[$name])) {
49 2
            self::$mockingStrategies[$name] = PluginHelper::load($name);
50
        }
51
52 4
        $fqcnOrAlias = $arguments[0];
53 4
        $alias = $arguments[1] ?? null;
54 4
        $mockingStrategy = self::$mockingStrategies[$name];
55
56 4
        return ProxyBuilderFactory::get($mockingStrategy)->getProxy($fqcnOrAlias, $alias);
57
    }
58
59
    /**
60
     * @param string $fqcnOrAlias
61
     * @param string|null $alias
62
     * @return MockObject|ProxyInterface
63
     */
64 3
    public static function phpunit(string $fqcnOrAlias, string $alias = null): ProxyInterface
65
    {
66
        /** @var ProxyInterface|ProxyTrait $proxy */
67 3
        $proxy = self::__callStatic('phpunit', [$fqcnOrAlias, $alias]);
68
69 3
        if (null !== $testCase = self::getCurrentTestCase()) {
70 3
            $testCase->registerMockObject($proxy->__moka_getMock());
1 ignored issue
show
Bug introduced by
The method __moka_getMock does only exist in Moka\Proxy\ProxyTrait, but not in Moka\Proxy\ProxyInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
71
        }
72
73 3
        return $proxy;
74
    }
75
76
    /**
77
     * @param string $fqcnOrAlias
78
     * @param string|null $alias
79
     * @return ObjectProphecy|ProxyInterface
80
     */
81 2
    public static function prophecy(string $fqcnOrAlias, string $alias = null): ProxyInterface
82
    {
83
        /** @var ProxyInterface|ProxyTrait $proxy */
84 2
        $proxy = self::__callStatic('prophecy', [$fqcnOrAlias, $alias]);
85
86 2
        if (null !== $testCase = self::getCurrentTestCase()) {
87 2
            $prophetProperty = new \ReflectionProperty(
88 2
                TestCase::class,
89 2
                'prophet'
90
            );
91
92 2
            $prophetProperty->setAccessible(true);
93 2
            if (null === $prophet = $prophetProperty->getValue($testCase)) {
94 2
                $prophet = new Prophet();
95 2
                $prophetProperty->setValue($testCase, $prophet);
96
            }
97
98 2
            $propheciesProperty = new \ReflectionProperty(
99 2
                Prophet::class,
100 2
                'prophecies'
101
            );
102 2
            $propheciesProperty->setAccessible(true);
103
104
            /** @var ObjectProphecy[] $prophecies */
105 2
            $prophecies = $propheciesProperty->getValue($prophet) ?: [];
106 2
            $prophecies[] = $proxy->__moka_getMock();
107
108 2
            $propheciesProperty->setValue($prophet, $prophecies);
109
        }
110
111 2
        return $proxy;
112
    }
113
114
    /**
115
     * @return void
116
     */
117 1
    public static function clean()
118
    {
119 1
        ProxyBuilderFactory::reset();
120
    }
121
122
    /**
123
     * @return TestCase|null
124
     */
125 4
    private static function getCurrentTestCase()
126
    {
127 4
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
128 4
        foreach ($backtrace as $frame) {
129 4
            if (!isset($frame['object'])) {
130 4
                continue;
131
            }
132
133 4
            $object = $frame['object'];
134 4
            if ($object instanceof TestCase) {
135 4
                return $object;
136
            }
137
138
            // @codeCoverageIgnoreStart
139
            return null;
140
            // @codeCoverageIgnoreEnd
141
        }
142
143
        // @codeCoverageIgnoreStart
144
        return null;
145
        // @codeCoverageIgnoreEnd
146
    }
147
}
148