Passed
Pull Request — master (#24)
by Dmitriy
01:34
created

testLastMatchedHostProtocolRelativeSchemeAbsoluteUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 12
rs 10
1
<?php
2
3
namespace Yiisoft\Router\FastRoute\Tests;
4
5
use Nyholm\Psr7\ServerRequest;
6
use PHPUnit\Framework\TestCase;
7
use Yiisoft\Router\FastRoute\UrlGenerator;
8
use Yiisoft\Router\FastRoute\UrlMatcher;
9
use Yiisoft\Router\Group;
10
use Yiisoft\Router\Route;
11
use Yiisoft\Router\RouteNotFoundException;
12
use Yiisoft\Router\UrlGeneratorInterface;
13
use Yiisoft\Router\UrlMatcherInterface;
14
use Yiisoft\Router\RouteCollection;
15
16
final class UrlGeneratorTest extends TestCase
17
{
18
    private function createUrlGenerator(array $routes, UrlMatcherInterface $matcher = null): UrlGeneratorInterface
19
    {
20
        $matcher = $matcher ?? $this->createMatcher($routes);
21
        return new UrlGenerator($matcher);
22
    }
23
24
    private function createMatcher(array $routes): UrlMatcherInterface
25
    {
26
        $container = new DummyContainer();
27
        $rootGroup = Group::create(null, $routes, $container);
28
        return new UrlMatcher(new RouteCollection($rootGroup));
29
    }
30
31
    public function testSimpleRouteGenerated(): void
32
    {
33
        $routes = [
34
            Route::get('/home/index')->name('index'),
35
        ];
36
        $url = $this->createUrlGenerator($routes)->generate('index');
37
38
        $this->assertEquals('/home/index', $url);
39
    }
40
41
    public function testRouteWithoutNameNotFound(): void
42
    {
43
        $routes = [
44
            Route::get('/home/index'),
45
            Route::get('/index'),
46
            Route::get('index'),
47
        ];
48
        $urlGenerator = $this->createUrlGenerator($routes);
49
50
        $this->expectException(RouteNotFoundException::class);
51
        $urlGenerator->generate('index');
52
    }
53
54
    public function testParametersSubstituted(): void
55
    {
56
        $routes = [
57
            Route::get('/view/{id:\d+}/{text:~[\w]+}#{tag:\w+}')->name('view'),
58
        ];
59
        $url = $this->createUrlGenerator($routes)->generate('view', ['id' => 100, 'tag' => 'yii', 'text' => '~test']);
60
61
        $this->assertEquals('/view/100/~test#yii', $url);
62
    }
63
64
    public function testExceptionThrownIfParameterPatternDoesntMatch(): void
65
    {
66
        $routes = [
67
            Route::get('/view/{id:\w+}')->name('view'),
68
        ];
69
        $urlGenerator = $this->createUrlGenerator($routes);
70
71
        $this->expectExceptionMessage('Parameter value for [id] did not match the regex `\w+`');
72
        $urlGenerator->generate('view', ['id' => null]);
73
    }
74
75
    public function testExceptionThrownIfAnyParameterIsMissing(): void
76
    {
77
        $routes = [
78
            Route::get('/view/{id:\d+}/{value}')->name('view'),
79
        ];
80
        $urlGenerator = $this->createUrlGenerator($routes);
81
82
        $this->expectExceptionMessage('Route `view` expects at least parameter values for [id,value], but received [id]');
83
        $urlGenerator->generate('view', ['id' => 123]);
84
    }
85
86
    public function testGroupPrefixAppended(): void
87
    {
88
        $routes = [
89
            Group::create('/api', [
90
                Route::get('/post')->name('post/index'),
91
                Route::get('/post/{id}')->name('post/view'),
92
            ]),
93
        ];
94
        $urlGenerator = $this->createUrlGenerator($routes);
95
96
        $url = $urlGenerator->generate('post/index');
97
        $this->assertEquals('/api/post', $url);
98
99
        $url = $urlGenerator->generate('post/view', ['id' => 42]);
100
        $this->assertEquals('/api/post/42', $url);
101
    }
102
103
    public function testNestedGroupsPrefixAppended(): void
104
    {
105
        $routes = [
106
            Group::create('/api', [
107
                Group::create('/v1', [
108
                    Route::get('/user')->name('api-v1-user/index'),
109
                    Route::get('/user/{id}')->name('api-v1-user/view'),
110
                    Group::create('/news', [
111
                        Route::get('/post')->name('api-v1-news-post/index'),
112
                        Route::get('/post/{id}')->name('api-v1-news-post/view'),
113
                    ]),
114
                    Group::create('/blog', [
115
                        Route::get('/post')->name('api-v1-blog-post/index'),
116
                        Route::get('/post/{id}')->name('api-v1-blog-post/view'),
117
                    ]),
118
                    Route::get('/note')->name('api-v1-note/index'),
119
                    Route::get('/note/{id}')->name('api-v1-note/view'),
120
                ])
121
            ])
122
        ];
123
        $urlGenerator = $this->createUrlGenerator($routes);
124
125
        $url = $urlGenerator->generate('api-v1-user/index');
126
        $this->assertEquals('/api/v1/user', $url);
127
128
        $url = $urlGenerator->generate('api-v1-user/view', ['id' => 42]);
129
        $this->assertEquals('/api/v1/user/42', $url);
130
131
        $url = $urlGenerator->generate('api-v1-news-post/index');
132
        $this->assertEquals('/api/v1/news/post', $url);
133
134
        $url = $urlGenerator->generate('api-v1-news-post/view', ['id' => 42]);
135
        $this->assertEquals('/api/v1/news/post/42', $url);
136
137
        $url = $urlGenerator->generate('api-v1-blog-post/index');
138
        $this->assertEquals('/api/v1/blog/post', $url);
139
140
        $url = $urlGenerator->generate('api-v1-blog-post/view', ['id' => 42]);
141
        $this->assertEquals('/api/v1/blog/post/42', $url);
142
143
        $url = $urlGenerator->generate('api-v1-note/index');
144
        $this->assertEquals('/api/v1/note', $url);
145
146
        $url = $urlGenerator->generate('api-v1-note/view', ['id' => 42]);
147
        $this->assertEquals('/api/v1/note/42', $url);
148
    }
149
150
    public function testExtraParametersAddedAsQueryString(): void
151
    {
152
        $routes = [
153
            Route::get('/test/{name}')
154
                ->name('test')
155
        ];
156
157
        $url = $this->createUrlGenerator($routes)->generate('test', ['name' => 'post', 'id' => 12, 'sort' => 'asc']);
158
        $this->assertEquals('/test/post?id=12&sort=asc', $url);
159
    }
160
161
    public function testDefaultNotUsedForOptionalParameter(): void
162
    {
163
        $routes = [
164
            Route::get('/[{name}]')
165
                ->name('defaults')
166
                ->defaults(['name' => 'default'])
167
        ];
168
169
        $url = $this->createUrlGenerator($routes)->generate('defaults');
170
        $this->assertEquals('/', $url);
171
    }
172
173
    public function testValueUsedForOptionalParameter(): void
174
    {
175
        $routes = [
176
            Route::get('/[{name}]')
177
                ->name('defaults')
178
                ->defaults(['name' => 'default'])
179
        ];
180
181
        $url = $this->createUrlGenerator($routes)->generate('defaults', ['name' => 'test']);
182
        $this->assertEquals('/test', $url);
183
    }
184
185
    public function testDefaultNotUsedForRequiredParameter(): void
186
    {
187
        $routes = [
188
            Route::get('/{name}')
189
                ->name('defaults')
190
                ->defaults(['name' => 'default'])
191
        ];
192
193
        $this->expectExceptionMessage('Route `defaults` expects at least parameter values for [name], but received []');
194
        $this->createUrlGenerator($routes)->generate('defaults');
195
    }
196
197
    /**
198
     * Host specified in generateAbsolute() should override host specified in route
199
     */
200
    public function testAbsoluteUrlHostOverride(): void
201
    {
202
        $routes = [
203
            Route::get('/home/index')->name('index')->host('http://test.com'),
204
        ];
205
        $url = $this->createUrlGenerator($routes)->generateAbsolute('index', [], null, 'http://mysite.com');
206
207
        $this->assertEquals('http://mysite.com/home/index', $url);
208
    }
209
210
    /**
211
     * Trailing slash in host argument of generateAbsolute() should not break URL generated
212
     */
213
    public function testAbsoluteUrlHostOverrideWithTrailingSlash(): void
214
    {
215
        $routes = [
216
            Route::get('/home/index')->name('index')->host('http://test.com'),
217
        ];
218
        $url = $this->createUrlGenerator($routes)->generateAbsolute('index', [], null, 'http://mysite.com/');
219
220
        $this->assertEquals('http://mysite.com/home/index', $url);
221
    }
222
223
    /**
224
     * Scheme specified in generateAbsolute() should override scheme specified in route
225
     */
226
    public function testAbsoluteUrlSchemeOverrideHostInRouteScheme(): void
227
    {
228
        $routes = [
229
            Route::get('/home/index')->name('index')->host('http://test.com'),
230
        ];
231
        $url = $this->createUrlGenerator($routes)->generateAbsolute('index', [], 'https');
232
233
        $this->assertEquals('https://test.com/home/index', $url);
234
    }
235
236
    /**
237
     * Scheme specified in generateAbsolute() should override scheme specified in method
238
     */
239
    public function testAbsoluteUrlSchemeOverrideHostInMethodScheme(): void
240
    {
241
        $routes = [
242
            Route::get('/home/index')->name('index'),
243
        ];
244
        $url = $this->createUrlGenerator($routes)->generateAbsolute('index', [], 'https', 'http://test.com');
245
246
        $this->assertEquals('https://test.com/home/index', $url);
247
    }
248
249
    /**
250
     * Scheme specified in generateAbsolute() should override scheme specified in the matched host
251
     */
252
    public function testAbsoluteUrlSchemeOverrideLastMatchedHostScheme(): void
253
    {
254
        $request = new ServerRequest('GET', 'http://test.com/home/index');
255
        $routes = [
256
            Route::get('/home/index')->name('index'),
257
        ];
258
        $matcher = $this->createMatcher($routes);
259
        $matcher->match($request);
260
        $url = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index', [], 'https');
261
262
        $this->assertEquals('https://test.com/home/index', $url);
263
    }
264
265
    /**
266
     * If there's host specified in route, it should be used unless there's host parameter in generateAbsolute()
267
     */
268
    public function testAbsoluteUrlWithHostInRoute(): void
269
    {
270
        $routes = [
271
            Route::get('/home/index')->name('index')->host('http://test.com'),
272
        ];
273
        $url = $this->createUrlGenerator($routes)->generateAbsolute('index');
274
275
        $this->assertEquals('http://test.com/home/index', $url);
276
    }
277
278
    /**
279
     * Trailing slash in route host should not break URL generated
280
     */
281
    public function testAbsoluteUrlWithTrailingSlashHostInRoute(): void
282
    {
283
        $routes = [
284
            Route::get('/home/index')->name('index')->host('http://test.com/'),
285
        ];
286
        $url = $this->createUrlGenerator($routes)->generateAbsolute('index');
287
288
        $this->assertEquals('http://test.com/home/index', $url);
289
    }
290
291
    /**
292
     * Last matched host is used for absolute URL generation in case
293
     * host is not specified in either route or createUrlGenerator()
294
     */
295
    public function testLastMatchedHostUsedForAbsoluteUrl(): void
296
    {
297
        $request = new ServerRequest('GET', 'http://test.com/home/index');
298
        $routes = [
299
            Route::get('/home/index')->name('index'),
300
        ];
301
302
        $matcher = $this->createMatcher($routes);
303
        $matcher->match($request);
304
        $url = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index');
305
306
        $this->assertEquals('http://test.com/home/index', $url);
307
    }
308
309
    /**
310
     * If there's non-standard port used in last matched host,
311
     * it should end up in the URL generated
312
     */
313
    public function testLastMatchedHostWithPortUsedForAbsoluteUrl(): void
314
    {
315
        $request = new ServerRequest('GET', 'http://test.com:8080/home/index');
316
        $routes = [
317
            Route::get('/home/index')->name('index'),
318
        ];
319
320
        $matcher = $this->createMatcher($routes);
321
        $matcher->match($request);
322
        $url = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index');
323
324
        $this->assertEquals('http://test.com:8080/home/index', $url);
325
    }
326
327
    /**
328
     * Schema from route host should have more priority than schema from last matched request.
329
     */
330
    public function testHostInRouteWithProtocolRelativeSchemeAbsoluteUrl(): void
331
    {
332
        $request = new ServerRequest('GET', 'http://test.com/home/index');
333
        $routes = [
334
            Route::get('/home/index')->name('index')->host('//test.com'),
335
        ];
336
337
        $matcher = $this->createMatcher($routes);
338
        $matcher->match($request);
339
        $url = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index');
340
341
        $this->assertEquals('//test.com/home/index', $url);
342
    }
343
344
    /**
345
     * Schema from generateAbsolute() should have more priority than both
346
     * route and last matched request.
347
     */
348
    public function testHostInMethodWithProtocolRelativeSchemeAbsoluteUrl(): void
349
    {
350
        $request = new ServerRequest('GET', 'http://test.com/home/index');
351
        $routes = [
352
            Route::get('/home/index')->name('index')->host('//mysite.com'),
353
        ];
354
355
        $matcher = $this->createMatcher($routes);
356
        $matcher->match($request);
357
        $url = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index', [], null, '//test.com');
358
359
        $this->assertEquals('//test.com/home/index', $url);
360
    }
361
362
    public function testHostInRouteProtocolRelativeSchemeAbsoluteUrl(): void
363
    {
364
        $request = new ServerRequest('GET', 'http://test.com/home/index');
365
        $routes = [
366
            Route::get('/home/index')->name('index')->host('http://test.com'),
367
            Route::get('/home/view')->name('view')->host('test.com'),
368
        ];
369
370
        $matcher = $this->createMatcher($routes);
371
        $matcher->match($request);
372
        $url1 = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index', [], '');
373
        $url2 = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('view', [], '');
374
375
        $this->assertEquals('//test.com/home/index', $url1);
376
        $this->assertEquals('//test.com/home/view', $url2);
377
    }
378
379
    public function testHostInMethodProtocolRelativeSchemeAbsoluteUrl(): void
380
    {
381
        $request = new ServerRequest('GET', 'http://test.com/home/index');
382
        $routes = [
383
            Route::get('/home/index')->name('index')->host('//mysite.com'),
384
        ];
385
386
        $matcher = $this->createMatcher($routes);
387
        $matcher->match($request);
388
        $url1 = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index', [], '', 'http://test.com');
389
        $url2 = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index', [], '', 'test.com');
390
391
        $this->assertEquals('//test.com/home/index', $url1);
392
        $this->assertEquals('//test.com/home/index', $url2);
393
    }
394
395
    public function testLastMatchedHostProtocolRelativeSchemeAbsoluteUrl(): void
396
    {
397
        $request = new ServerRequest('GET', 'http://test.com/home/index');
398
        $routes = [
399
            Route::get('/home/index')->name('index'),
400
        ];
401
402
        $matcher = $this->createMatcher($routes);
403
        $matcher->match($request);
404
        $url = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index', [], '');
405
406
        $this->assertEquals('//test.com/home/index', $url);
407
    }
408
409
    public function testFallbackAbsoluteUrl(): void
410
    {
411
        $routes = [
412
            Route::get('/home/index')->name('index'),
413
        ];
414
415
        $matcher = $this->createMatcher($routes);
416
        $url = $this->createUrlGenerator($routes, $matcher)->generateAbsolute('index');
417
418
        $this->assertEquals('/home/index', $url);
419
    }
420
}
421