AbstractTakeThanMatcher::bench()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 2
b 0
f 0
nc 1
nop 2
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace loophp\phpspectime\Matcher;
6
7
use loophp\nanobench\BenchmarkFactoryInterface;
8
use PhpSpec\Exception\Example\MatcherException;
9
use PhpSpec\Exception\Fracture\MethodNotFoundException;
10
use PhpSpec\Formatter\Presenter\Presenter;
11
use PhpSpec\Matcher\Matcher;
12
use PhpSpec\Wrapper\DelayedCall;
13
use PhpSpec\Wrapper\Unwrapper;
14
15
use function call_user_func;
16
use function count;
17
use function get_class;
18
use function in_array;
19
20
abstract class AbstractTakeThanMatcher implements Matcher
21
{
22
    /**
23
     * @var BenchmarkFactoryInterface
24
     */
25
    protected $benchmarkFactory;
26
27
    protected $keywords;
28
29
    /**
30
     * @var array
31
     */
32
    protected $params;
33
34
    /**
35
     * @var \PhpSpec\Formatter\Presenter\Presenter
36
     */
37
    protected $presenter;
38
39
    /**
40
     * @var \PhpSpec\Wrapper\Unwrapper
41
     */
42
    protected $unwrapper;
43
44 25
    public function __construct(
45
        Unwrapper $unwrapper,
46
        Presenter $presenter,
47
        BenchmarkFactoryInterface $benchmarkFactory,
48
        array $params
49
    ) {
50 25
        $this->unwrapper = $unwrapper;
51 25
        $this->presenter = $presenter;
52 25
        $this->benchmarkFactory = $benchmarkFactory;
53 25
        $this->params = $params;
54 25
    }
55
56
    /**
57
     * @return float|string
58
     */
59 12
    public function bench(callable $callable, array $arguments)
60
    {
61
        return $this
62 12
            ->benchmarkFactory
63 12
            ->fromCallable($callable, ...$arguments)
64 12
            ->run()
65 12
            ->getDuration()
66 12
            ->as($this->params['timeunit']);
67
    }
68
69 3
    public function getPriority(): int
70
    {
71 3
        return 1;
72
    }
73
74 6
    public function negativeMatch(string $name, $subject, array $arguments): DelayedCall
75
    {
76 6
        return $this->getDelayedCall([$this, 'verifyNegative'], $subject, $arguments);
77
    }
78
79 9
    public function positiveMatch(string $name, $subject, array $arguments): DelayedCall
80
    {
81 9
        return $this->getDelayedCall([$this, 'verifyPositive'], $subject, $arguments);
82
    }
83
84
    /**
85
     * @psalm-suppress UndefinedDocblockClass
86
     *
87
     * @param mixed $subject
88
     */
89 2
    public function supports(string $name, $subject, array $arguments): bool
90
    {
91 2
        return in_array($name, $this->keywords, true) && 1 === count($arguments);
92
    }
93
94 15
    protected function getDelayedCall(callable $check, $subject, array $arguments): DelayedCall
95
    {
96 15
        $timeInSeconds = $this->getParameters($arguments);
97 13
        $unwrapper = $this->unwrapper;
98
99 13
        return new DelayedCall(
100
            static function ($method, $arguments) use ($check, $subject, $timeInSeconds, $unwrapper) {
101 13
                $arguments = $unwrapper->unwrapAll($arguments);
102
103 13
                $methodName = $arguments[0];
104 13
                $arguments = $arguments[1] ?? [];
105 13
                $callable = [$subject, $methodName];
106
107 13
                [$class, $methodName] = [$subject, $methodName];
108
109 13
                if (!method_exists($class, $methodName) && !method_exists($class, '__call')) {
110 1
                    throw new MethodNotFoundException(
111 1
                        sprintf('Method %s::%s not found.', get_class($class), $methodName),
112
                        $class,
113
                        $methodName,
114
                        $arguments
115
                    );
116
                }
117
118 12
                return call_user_func($check, $callable, $arguments, $timeInSeconds);
119 13
            }
120
        );
121
    }
122
123
    /**
124
     * @return float
125
     */
126 10
    protected function getParameters(array $arguments)
127
    {
128 10
        $timeInSeconds = current($arguments);
129
130 10
        if (!is_numeric($timeInSeconds)) {
131 1
            throw new MatcherException(
132 1
                sprintf(
133
                    "Wrong argument provided in throw matcher.\n" .
134
                    "Fully qualified classname or exception instance expected,\n" .
135 1
                    'Got %s.',
136 1
                    $this->presenter->presentValue($arguments[0])
137
                )
138
            );
139
        }
140
141 9
        return $timeInSeconds;
142
    }
143
}
144