Test Failed
Branch master (4153a4)
by Divine Niiquaye
13:02
created

RouteBench::runScenario()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 15
rs 9.9
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Flight Routing.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Flight\Routing\Tests\Benchmarks;
19
20
use Flight\Routing\Exceptions\MethodNotAllowedException;
21
use Flight\Routing\Interfaces\RouteMatcherInterface;
22
use Nyholm\Psr7\Uri;
23
24
/**
25
 * @Warmup(2)
26
 * @Revs(100)
27
 * @Iterations(5)
28
 * @BeforeClassMethods({"before"})
29
 */
30
abstract class RouteBench
31
{
32
    protected const MAX_ROUTES = 400;
33
    protected const CACHE_FILE = __DIR__.'/../Fixtures/compiled_test.php';
34
35
    /** @var array<string,RouteMatcherInterface> */
36
    private array $dispatchers = [];
37
38
    public static function before(): void
39
    {
40
        if (\file_exists(self::CACHE_FILE)) {
41
            @\unlink(self::CACHE_FILE);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

41
            /** @scrutinizer ignore-unhandled */ @\unlink(self::CACHE_FILE);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
42
        }
43
    }
44
45
    /** @return \Generator<string,array<string,mixed>> */
46
    abstract public function provideStaticRoutes(): iterable;
47
48
    /** @return \Generator<string,array<string,mixed>> */
49
    abstract public function provideDynamicRoutes(): iterable;
50
51
    /** @return \Generator<string,array<string,mixed>> */
52
    abstract public function provideOtherScenarios(): iterable;
53
54
    /** @return \Generator<string,array<int,mixed>> */
55
    public function provideAllScenarios(): iterable
56
    {
57
        yield 'static(first,middle,last,invalid-method)' => \array_values(\iterator_to_array($this->provideStaticRoutes()));
58
        yield 'dynamic(first,middle,last,invalid-method)' => \array_values(\iterator_to_array($this->provideDynamicRoutes()));
59
        yield 'others(non-existent,...)' => \array_values(\iterator_to_array($this->provideOtherScenarios()));
60
    }
61
62
    /** @return \Generator<string,array<string,string>> */
63
    public function provideDispatcher(): iterable
64
    {
65
        yield 'not_cached' => ['dispatcher' => 'not_cached'];
66
        yield 'cached' => ['dispatcher' => 'cached'];
67
    }
68
69
    public function initDispatchers(): void
70
    {
71
        $this->dispatchers['not_cached'] = $this->createDispatcher();
72
        $this->dispatchers['cached'] = $this->createDispatcher(self::CACHE_FILE);
73
    }
74
75
    /**
76
     * @BeforeMethods({"initDispatchers"})
77
     * @ParamProviders({"provideDispatcher", "provideStaticRoutes"})
78
     */
79
    public function benchStaticRoutes(array $params): void
80
    {
81
        $this->runScenario($params);
82
    }
83
84
    /**
85
     * @BeforeMethods({"initDispatchers"})
86
     * @ParamProviders({"provideDispatcher", "provideDynamicRoutes"})
87
     */
88
    public function benchDynamicRoutes(array $params): void
89
    {
90
        $this->runScenario($params);
91
    }
92
93
    /**
94
     * @BeforeMethods({"initDispatchers"})
95
     * @ParamProviders({"provideDispatcher", "provideOtherScenarios"})
96
     */
97
    public function benchOtherRoutes(array $params): void
98
    {
99
        $this->runScenario($params);
100
    }
101
102
    /**
103
     * @BeforeMethods({"initDispatchers"})
104
     * @ParamProviders({"provideDispatcher", "provideAllScenarios"})
105
     */
106
    public function benchAll(array $params): void
107
    {
108
        $dispatcher = \array_shift($params);
109
110
        foreach ($params as $param) {
111
            $this->runScenario($param + \compact('dispatcher'));
112
        }
113
    }
114
115
    /**
116
     * @ParamProviders({"provideAllScenarios"})
117
     * @Revs(4)
118
     */
119
    public function benchWithRouter(array $params): void
120
    {
121
        $this->dispatchers['router'] = $this->createDispatcher();
122
123
        foreach ($params as $param) {
124
            $this->runScenario($param + ['dispatcher' => 'router']);
125
        }
126
    }
127
128
    /**
129
     * @ParamProviders({"provideAllScenarios"})
130
     * @Revs(4)
131
     */
132
    public function benchWithCache(array $params): void
133
    {
134
        $this->dispatchers['cached'] = $this->createDispatcher(self::CACHE_FILE);
135
136
        foreach ($params as $param) {
137
            $this->runScenario($param + ['dispatcher' => 'cached']);
138
        }
139
    }
140
141
    abstract protected function createDispatcher(string $cache = null): RouteMatcherInterface;
142
143
    /**
144
     * @param array<string,array<int,mixed>|string> $params
145
     */
146
    private function runScenario(array $params): void
147
    {
148
        try {
149
            $dispatcher = $this->dispatchers[$params['dispatcher']];
150
            $result = $params['result'] === $dispatcher->match($params['method'], new Uri($params['route']));
0 ignored issues
show
Bug introduced by
It seems like $params['route'] can also be of type array<integer,mixed>; however, parameter $uri of Nyholm\Psr7\Uri::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

150
            $result = $params['result'] === $dispatcher->match($params['method'], new Uri(/** @scrutinizer ignore-type */ $params['route']));
Loading history...
151
        } catch (MethodNotAllowedException $e) {
152
            $result = $params['result'] === $e::class;
153
        }
154
155
        \assert($result, new \RuntimeException(
156
            \sprintf(
157
                'Benchmark "%s: %s" failed with method "%s"',
158
                $params['dispatcher'],
0 ignored issues
show
Bug introduced by
It seems like $params['dispatcher'] can also be of type array<integer,mixed>; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

158
                /** @scrutinizer ignore-type */ $params['dispatcher'],
Loading history...
159
                $params['route'],
160
                $params['method']
161
            )
162
        ));
163
    }
164
}
165