Passed
Push — master ( b6b1fe...a07f0a )
by Anatoly
01:36
created

RouterTest::testMatchHttpMethods()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 34
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 22
nc 1
nop 0
dl 0
loc 34
rs 9.568
c 0
b 0
f 0
1
<?php
2
3
namespace Sunrise\Http\Router\Tests;
4
5
use Fig\Http\Message\RequestMethodInterface;
6
use PHPUnit\Framework\TestCase;
7
use Psr\Http\Server\RequestHandlerInterface;
8
use Sunrise\Http\Message\ResponseFactory;
9
use Sunrise\Http\Router\Exception\HttpExceptionInterface;
10
use Sunrise\Http\Router\Exception\MethodNotAllowedException;
11
use Sunrise\Http\Router\Exception\RouteNotFoundException;
12
use Sunrise\Http\Router\RouteCollection;
13
use Sunrise\Http\Router\RouteCollectionInterface;
14
use Sunrise\Http\Router\RouteInterface;
15
use Sunrise\Http\Router\Router;
16
use Sunrise\Http\Router\RouterInterface;
17
use Sunrise\Http\ServerRequest\ServerRequestFactory;
18
19
// fake middlewares
20
use Sunrise\Http\Router\Tests\Middleware\FooMiddlewareTest;
21
use Sunrise\Http\Router\Tests\Middleware\BarMiddlewareTest;
22
use Sunrise\Http\Router\Tests\Middleware\BazMiddlewareTest;
23
use Sunrise\Http\Router\Tests\Middleware\QuxMiddlewareTest;
24
use Sunrise\Http\Router\Tests\Middleware\SetRequestAttributesWithoutRouteIdToResponseHeaderMiddlewareTest;
25
use Sunrise\Http\Router\Tests\Middleware\SetRouteIdFromRequestAttributesToResponseHeaderMiddlewareTest;
26
27
class RouterTest extends TestCase
28
{
29
	public function testConstructor()
30
	{
31
		$routes = new RouteCollection();
32
		$router = new Router($routes);
33
34
		$this->assertInstanceOf(RouterInterface::class, $router);
35
		$this->assertInstanceOf(RequestHandlerInterface::class, $router);
36
	}
37
38
	public function testGetMiddlewareStack()
39
	{
40
		$routes = new RouteCollection();
41
		$router = new Router($routes);
42
43
		$this->assertEquals([], $router->getMiddlewareStack());
44
	}
45
46
	public function testAddMiddleware()
47
	{
48
		$foo = new FooMiddlewareTest();
49
50
		$routes = new RouteCollection();
51
		$router = new Router($routes);
52
53
		$this->assertInstanceOf(RouterInterface::class, $router->addMiddleware($foo));
54
55
		$this->assertEquals([$foo], $router->getMiddlewareStack());
56
	}
57
58
	public function testAddSeveralMiddlewares()
59
	{
60
		$foo = new FooMiddlewareTest();
61
		$bar = new BarMiddlewareTest();
62
63
		$routes = new RouteCollection();
64
		$router = new Router($routes);
65
66
		$router->addMiddleware($foo);
67
		$router->addMiddleware($bar);
68
69
		$this->assertEquals([
70
			$foo,
71
			$bar,
72
		], $router->getMiddlewareStack());
73
	}
74
75
	public function testMatchSeveralRoutes()
76
	{
77
		$routes = new RouteCollection();
78
		$foo = $routes->get('foo', '/foo');
0 ignored issues
show
Unused Code introduced by
The assignment to $foo is dead and can be removed.
Loading history...
79
		$bar = $routes->get('bar', '/bar');
0 ignored issues
show
Unused Code introduced by
The assignment to $bar is dead and can be removed.
Loading history...
80
		$baz = $routes->get('baz', '/baz');
0 ignored issues
show
Unused Code introduced by
The assignment to $baz is dead and can be removed.
Loading history...
81
		$qux = $routes->get('qux', '/qux');
82
		$router = new Router($routes);
0 ignored issues
show
Unused Code introduced by
The assignment to $router is dead and can be removed.
Loading history...
83
84
		$route = $this->discoverRoute($routes, 'GET', '/qux');
85
		$this->assertEquals($qux, $route);
86
	}
87
88
	public function testMatchHttpMethods()
89
	{
90
		$routes = new RouteCollection();
91
92
		$foo = $routes->head('foo', '/foo');
93
		$bar = $routes->get('bar', '/bar');
94
		$baz = $routes->post('baz', '/baz');
95
96
		$route = $this->discoverRoute($routes, 'HEAD', '/foo');
97
		$this->assertEquals($foo, $route);
98
99
		$route = $this->discoverRoute($routes, 'GET', '/foo');
100
		$this->assertNull($route);
101
102
		$route = $this->discoverRoute($routes, 'POST', '/foo');
103
		$this->assertNull($route);
104
105
		$route = $this->discoverRoute($routes, 'GET', '/bar');
106
		$this->assertEquals($bar, $route);
107
108
		$route = $this->discoverRoute($routes, 'HEAD', '/bar');
109
		$this->assertNull($route);
110
111
		$route = $this->discoverRoute($routes, 'POST', '/bar');
112
		$this->assertNull($route);
113
114
		$route = $this->discoverRoute($routes, 'POST', '/baz');
115
		$this->assertEquals($baz, $route);
116
117
		$route = $this->discoverRoute($routes, 'HEAD', '/baz');
118
		$this->assertNull($route);
119
120
		$route = $this->discoverRoute($routes, 'GET', '/baz');
121
		$this->assertNull($route);
122
	}
123
124
	public function testMatchAttributes()
125
	{
126
		$routes = new RouteCollection();
127
		$routes->get('test', '/{foo}/{bar}/{baz}');
128
129
		$route = $this->discoverRoute($routes, 'GET', '/first/second/third');
130
		$this->assertEquals($route->getAttributes(), [
131
			'foo' => 'first',
132
			'bar' => 'second',
133
			'baz' => 'third',
134
		]);
135
136
		$route = $this->discoverRoute($routes, 'GET', '/');
137
		$this->assertNull($route);
138
139
		$route = $this->discoverRoute($routes, 'GET', '/first');
140
		$this->assertNull($route);
141
142
		$route = $this->discoverRoute($routes, 'GET', '/first/second');
143
		$this->assertNull($route);
144
145
		$route = $this->discoverRoute($routes, 'GET', '/first/second/third/fourth');
146
		$this->assertNull($route);
147
	}
148
149
	public function testMatchOptionalAttributes()
150
	{
151
		$routes = new RouteCollection();
152
		$routes->get('test', '/{foo}(/{bar}/{baz})/{qux}');
153
154
		$route = $this->discoverRoute($routes, 'GET', '/first/second');
155
		$this->assertEquals($route->getAttributes(), [
156
			'foo' => 'first',
157
			'qux' => 'second',
158
		]);
159
160
		$route = $this->discoverRoute($routes, 'GET', '/first/second/third/fourth');
161
		$this->assertEquals($route->getAttributes(), [
162
			'foo' => 'first',
163
			'bar' => 'second',
164
			'baz' => 'third',
165
			'qux' => 'fourth',
166
		]);
167
168
		$route = $this->discoverRoute($routes, 'GET', '/first');
169
		$this->assertNull($route);
170
171
		$route = $this->discoverRoute($routes, 'GET', '/first/second/third/fourth/fifth');
172
		$this->assertNull($route);
173
	}
174
175
	public function testMatchNestedOptionalAttributes()
176
	{
177
		$routes = new RouteCollection();
178
		$routes->get('test', '/{foo}(/{bar}(/{baz})/{qux})/{quux}');
179
180
		$route = $this->discoverRoute($routes, 'GET', '/first/second');
181
		$this->assertEquals($route->getAttributes(), [
182
			'foo' => 'first',
183
			'quux' => 'second',
184
		]);
185
186
		$route = $this->discoverRoute($routes, 'GET', '/first/second/third/fourth');
187
		$this->assertEquals($route->getAttributes(), [
188
			'foo' => 'first',
189
			'bar' => 'second',
190
			'qux' => 'third',
191
			'quux' => 'fourth',
192
		]);
193
194
		$route = $this->discoverRoute($routes, 'GET', '/first/second/third/fourth/fifth');
195
		$this->assertEquals($route->getAttributes(), [
196
			'foo' => 'first',
197
			'bar' => 'second',
198
			'baz' => 'third',
199
			'qux' => 'fourth',
200
			'quux' => 'fifth',
201
		]);
202
203
		$route = $this->discoverRoute($routes, 'GET', '/first');
204
		$this->assertNull($route);
205
206
		$route = $this->discoverRoute($routes, 'GET', '/first/second/third');
207
		$this->assertNull($route);
208
	}
209
210
	public function testMatchPatterns()
211
	{
212
		$routes = new RouteCollection();
213
214
		$routes->get('test', '/{foo}/{bar}(/{baz})')
215
			->addPattern('foo', '[0-9]+')
216
			->addPattern('bar', '[a-z]+')
217
			->addPattern('baz', '.*?');
218
219
		$route = $this->discoverRoute($routes, 'GET', '/1990/Surgut/Tyumen');
220
		$this->assertEquals($route->getAttributes(), [
221
			'foo' => '1990',
222
			'bar' => 'Surgut',
223
			'baz' => 'Tyumen',
224
		]);
225
226
		$route = $this->discoverRoute($routes, 'GET', '/1990/Surgut/Tyumen/Moscow');
227
		$this->assertEquals($route->getAttributes(), [
228
			'foo' => '1990',
229
			'bar' => 'Surgut',
230
			'baz' => 'Tyumen/Moscow',
231
		]);
232
233
		$route = $this->discoverRoute($routes, 'GET', '/Oops/Surgut/Tyumen/Moscow');
234
		$this->assertNull($route);
235
236
		$route = $this->discoverRoute($routes, 'GET', '/1990/2018/Moscow');
237
		$this->assertNull($route);
238
	}
239
240
	public function testMatchRouteNotFoundException()
241
	{
242
		$request = (new ServerRequestFactory)
243
		->createServerRequest('GET', '/oops');
244
245
		$routes = new RouteCollection();
246
		$routes->get('test', '/');
247
		$router = new Router($routes);
248
249
		$this->expectException(RouteNotFoundException::class);
250
		$router->match($request);
251
	}
252
253
	public function testMatchMethodNotAllowedException()
254
	{
255
		$request = (new ServerRequestFactory)
256
		->createServerRequest('POST', '/');
257
258
		$routes = new RouteCollection();
259
		$routes->route('test', '/', ['HEAD', 'GET', 'OPTIONS']);
260
		$router = new Router($routes);
261
262
		$this->expectException(MethodNotAllowedException::class);
263
264
		try {
265
			$router->match($request);
266
		} catch (MethodNotAllowedException $e) {
267
			$this->assertEquals(['HEAD', 'GET', 'OPTIONS'], $e->getAllowedMethods());
268
			throw $e;
269
		}
270
	}
271
272
	public function testHandle()
273
	{
274
		$routes = new RouteCollection();
275
276
		$routes->get('test', '/{foo}/{bar}/{baz}')
277
		->addMiddleware(new SetRequestAttributesWithoutRouteIdToResponseHeaderMiddlewareTest())
278
		->addMiddleware(new SetRouteIdFromRequestAttributesToResponseHeaderMiddlewareTest())
279
		->addMiddleware(new BazMiddlewareTest())
280
		->addMiddleware(new QuxMiddlewareTest());
281
282
		$router = new Router($routes);
283
		$router->addMiddleware(new FooMiddlewareTest());
284
		$router->addMiddleware(new BarMiddlewareTest());
285
286
		$request = (new ServerRequestFactory)
287
		->createServerRequest('GET', '/first/second/third');
288
289
		$response = $router->handle($request);
290
291
		$this->assertEquals(['test'], $response->getHeader('x-route-id'));
292
293
		$this->assertEquals(['first, second, third'], $response->getHeader('x-request-attributes'));
294
295
		$this->assertEquals([
296
			'qux',
297
			'baz',
298
			'bar',
299
			'foo',
300
		], $response->getHeader('x-middleware'));
301
	}
302
303
	public function testExceptions()
304
	{
305
		$request = (new ServerRequestFactory)
306
		->createServerRequest('GET', '/');
307
308
		$routeNotFoundException = new RouteNotFoundException($request);
309
		$this->assertInstanceOf(HttpExceptionInterface::class, $routeNotFoundException);
310
		$this->assertInstanceOf(\RuntimeException::class, $routeNotFoundException);
311
312
		$methodNotAllowedException = new MethodNotAllowedException($request, ['HEAD', 'GET']);
313
		$this->assertInstanceOf(HttpExceptionInterface::class, $methodNotAllowedException);
314
		$this->assertInstanceOf(\RuntimeException::class, $methodNotAllowedException);
315
		$this->assertEquals(['HEAD', 'GET'], $methodNotAllowedException->getAllowedMethods());
316
	}
317
318
	private function discoverRoute(RouteCollectionInterface $routes, string $method, string $uri) : ?RouteInterface
319
	{
320
		$router = new Router($routes);
321
322
		$request = (new ServerRequestFactory)
323
		->createServerRequest($method, $uri);
324
325
		try {
326
			return $router->match($request);
327
		} catch (HttpExceptionInterface $error) {
328
			return null;
329
		}
330
	}
331
}
332