Passed
Pull Request — master (#24)
by
unknown
01:33
created

testDefaultNotUsedForOptionalParameter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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