Passed
Push — master ( a7f03b...b76a97 )
by Dan
01:56
created

MockFactory::newPartialMock()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 12
nc 4
nop 3
dl 0
loc 21
rs 9.8666
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Nopolabs\Test;
5
6
7
use PHPUnit\Framework\TestCase;
8
use PHPUnit_Framework_MockObject_MockBuilder;
9
use PHPUnit_Framework_MockObject_MockObject;
10
use ReflectionClass;
11
use ReflectionMethod;
12
13
class MockFactory
14
{
15
    /** @var TestCase */
16
    private $testCase;
17
18
    public function __construct(TestCase $testCase)
19
    {
20
        $this->testCase = $testCase;
21
    }
22
23
    public function newPartialMock(
24
        string $className,
25
        array $expectedMethods,
26
        array $constructorArgs = null): PHPUnit_Framework_MockObject_MockObject
27
    {
28
        $methods = $this->getMethodsToMock($className, $expectedMethods);
29
30
        $builder = $this->getMockBuilder($className);
31
        $builder->disableOriginalClone();
32
        $builder->disableArgumentCloning();
33
        $builder->disallowMockingUnknownTypes();
34
        if (!empty($methods)) {
35
            $builder->setMethods($methods);
36
        }
37
        if ($constructorArgs === null) {
38
            $builder->disableOriginalConstructor();
39
        } else {
40
            $builder->setConstructorArgs($constructorArgs);
41
        }
42
43
        return $builder->getMock();
44
    }
45
46
    protected function getMockBuilder(string $className) : PHPUnit_Framework_MockObject_MockBuilder
47
    {
48
        return $this->testCase->getMockBuilder($className);
49
    }
50
51
    private function getMethodsToMock(
52
        string $className,
53
        array $expectedMethods) : array
54
    {
55
        $missingMethods = $this->getMissingMethods($className);
56
57
        return array_unique(array_merge($expectedMethods, $missingMethods));
58
    }
59
60
    private function getMissingMethods(string $className) : array
61
    {
62
        $reflection = new ReflectionClass($className);
63
64
        if ($reflection->isInterface()) {
65
            return $this->getPublicMethods($reflection);
66
        }
67
68
        if ($reflection->isAbstract()) {
69
            return $this->getAbstractMethods($reflection);
70
        }
71
72
        return [];
73
    }
74
75
    private function getPublicMethods(ReflectionClass $reflection) : array
76
    {
77
        return $this->getReflectedMethods($reflection, ReflectionMethod::IS_PUBLIC);
78
    }
79
80
    private function getAbstractMethods(ReflectionClass $reflection) : array
81
    {
82
        return $this->getReflectedMethods($reflection, ReflectionMethod::IS_ABSTRACT);
83
    }
84
85
    private function getReflectedMethods(ReflectionClass $reflection, int $filter) : array
86
    {
87
        return array_map(function(ReflectionMethod $method) {
88
            return $method->name;
89
        }, $reflection->getMethods($filter));
90
    }
91
}