Issues (120)

tests/Benchmarks/RouteBench.php (3 issues)

1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of Flight Routing.
5
 *
6
 * PHP version 8.0 and above required
7
 *
8
 * @author    Divine Niiquaye Ibok <[email protected]>
9
 * @copyright 2019 Divine Niiquaye Ibok (https://divinenii.com/)
10
 * @license   https://opensource.org/licenses/BSD-3-Clause License
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 */
15
16
namespace Flight\Routing\Tests\Benchmarks;
17
18
use Flight\Routing\Exceptions\MethodNotAllowedException;
19
use Flight\Routing\Interfaces\RouteMatcherInterface;
20
use Nyholm\Psr7\Uri;
21
22
/**
23
 * @Warmup(2)
24
 * @Revs(100)
25
 * @Iterations(5)
26
 * @BeforeClassMethods({"before"})
27
 */
28
abstract class RouteBench
29
{
30
    protected const MAX_ROUTES = 400;
31
    protected const CACHE_FILE = __DIR__.'/../Fixtures/compiled_test.php';
32
33
    /** @var array<string,RouteMatcherInterface> */
34
    private array $dispatchers = [];
35
36
    public static function before(): void
37
    {
38
        if (\file_exists(self::CACHE_FILE)) {
39
            @\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

39
            /** @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...
40
        }
41
    }
42
43
    /** @return \Generator<string,array<string,mixed>> */
44
    abstract public function provideStaticRoutes(): iterable;
45
46
    /** @return \Generator<string,array<string,mixed>> */
47
    abstract public function provideDynamicRoutes(): iterable;
48
49
    /** @return \Generator<string,array<string,mixed>> */
50
    abstract public function provideOtherScenarios(): iterable;
51
52
    /** @return \Generator<string,array<int,mixed>> */
53
    public function provideAllScenarios(): iterable
54
    {
55
        yield 'static(first,middle,last,invalid-method)' => \array_values(\iterator_to_array($this->provideStaticRoutes()));
56
        yield 'dynamic(first,middle,last,invalid-method)' => \array_values(\iterator_to_array($this->provideDynamicRoutes()));
57
        yield 'others(non-existent,...)' => \array_values(\iterator_to_array($this->provideOtherScenarios()));
58
    }
59
60
    /** @return \Generator<string,array<string,string>> */
61
    public function provideDispatcher(): iterable
62
    {
63
        yield 'not_cached' => ['dispatcher' => 'not_cached'];
64
        yield 'cached' => ['dispatcher' => 'cached'];
65
    }
66
67
    public function initDispatchers(): void
68
    {
69
        $this->dispatchers['not_cached'] = $this->createDispatcher();
70
        $this->dispatchers['cached'] = $this->createDispatcher(self::CACHE_FILE);
71
    }
72
73
    /**
74
     * @BeforeMethods({"initDispatchers"})
75
     * @ParamProviders({"provideDispatcher", "provideStaticRoutes"})
76
     */
77
    public function benchStaticRoutes(array $params): void
78
    {
79
        $this->runScenario($params);
80
    }
81
82
    /**
83
     * @BeforeMethods({"initDispatchers"})
84
     * @ParamProviders({"provideDispatcher", "provideDynamicRoutes"})
85
     */
86
    public function benchDynamicRoutes(array $params): void
87
    {
88
        $this->runScenario($params);
89
    }
90
91
    /**
92
     * @BeforeMethods({"initDispatchers"})
93
     * @ParamProviders({"provideDispatcher", "provideOtherScenarios"})
94
     */
95
    public function benchOtherRoutes(array $params): void
96
    {
97
        $this->runScenario($params);
98
    }
99
100
    /**
101
     * @BeforeMethods({"initDispatchers"})
102
     * @ParamProviders({"provideDispatcher", "provideAllScenarios"})
103
     */
104
    public function benchAll(array $params): void
105
    {
106
        $dispatcher = \array_shift($params);
107
108
        foreach ($params as $param) {
109
            $this->runScenario($param + \compact('dispatcher'));
110
        }
111
    }
112
113
    /**
114
     * @ParamProviders({"provideAllScenarios"})
115
     * @Revs(4)
116
     */
117
    public function benchWithRouter(array $params): void
118
    {
119
        $this->dispatchers['router'] = $this->createDispatcher();
120
121
        foreach ($params as $param) {
122
            $this->runScenario($param + ['dispatcher' => 'router']);
123
        }
124
    }
125
126
    /**
127
     * @ParamProviders({"provideAllScenarios"})
128
     * @Revs(4)
129
     */
130
    public function benchWithCache(array $params): void
131
    {
132
        $this->dispatchers['cached'] = $this->createDispatcher(self::CACHE_FILE);
133
134
        foreach ($params as $param) {
135
            $this->runScenario($param + ['dispatcher' => 'cached']);
136
        }
137
    }
138
139
    abstract protected function createDispatcher(string $cache = null): RouteMatcherInterface;
140
141
    /**
142
     * @param array<string,array<int,mixed>|string> $params
143
     */
144
    private function runScenario(array $params): void
145
    {
146
        try {
147
            $dispatcher = $this->dispatchers[$params['dispatcher']];
148
            $result = $params['result'] === $dispatcher->match($params['method'], new Uri($params['route']));
0 ignored issues
show
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

148
            $result = $params['result'] === $dispatcher->match($params['method'], new Uri(/** @scrutinizer ignore-type */ $params['route']));
Loading history...
149
        } catch (MethodNotAllowedException $e) {
150
            $result = $params['result'] === $e::class;
151
        }
152
153
        \assert($result, new \RuntimeException(
154
            \sprintf(
155
                'Benchmark "%s: %s" failed with method "%s"',
156
                $params['dispatcher'],
0 ignored issues
show
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

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