|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare(strict_types=1); |
|
4
|
|
|
|
|
5
|
|
|
namespace GacelaTest\Unit\Router\Validators; |
|
6
|
|
|
|
|
7
|
|
|
use Gacela\Router\Validators\PathValidator; |
|
8
|
|
|
use Generator; |
|
9
|
|
|
use PHPUnit\Framework\TestCase; |
|
10
|
|
|
|
|
11
|
|
|
final class PathValidatorTest extends TestCase |
|
12
|
|
|
{ |
|
13
|
|
|
/** |
|
14
|
|
|
* @dataProvider validPathProvider |
|
15
|
|
|
*/ |
|
16
|
|
|
public function test_valid_paths(string $path): void |
|
17
|
|
|
{ |
|
18
|
|
|
self::assertTrue(PathValidator::isValid($path)); |
|
19
|
|
|
} |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* @dataProvider invalidPathProvider |
|
23
|
|
|
*/ |
|
24
|
|
|
public function test_invalid_paths(string $path): void |
|
25
|
|
|
{ |
|
26
|
|
|
self::assertFalse(PathValidator::isValid($path)); |
|
27
|
|
|
} |
|
28
|
|
|
|
|
29
|
|
|
public static function validPathProvider(): Generator |
|
30
|
|
|
{ |
|
31
|
|
|
yield 'root path' => ['/']; |
|
32
|
|
|
|
|
33
|
|
|
yield 'single segment' => ['users']; |
|
34
|
|
|
yield 'multiple segments' => ['api/v1/users']; |
|
35
|
|
|
yield 'single character' => ['a']; |
|
36
|
|
|
yield 'two segments' => ['a/b']; |
|
37
|
|
|
yield 'three segments' => ['x/y/z']; |
|
38
|
|
|
|
|
39
|
|
|
yield 'single mandatory param' => ['users/{id}']; |
|
40
|
|
|
yield 'multiple mandatory params' => ['posts/{postId}/comments/{commentId}']; |
|
41
|
|
|
yield 'only mandatory param' => ['{id}']; |
|
42
|
|
|
|
|
43
|
|
|
yield 'single optional param' => ['users/{id?}']; |
|
44
|
|
|
yield 'multiple optional params' => ['archive/{year?}/{month?}']; |
|
45
|
|
|
yield 'only optional param' => ['{id?}']; |
|
46
|
|
|
|
|
47
|
|
|
yield 'mandatory then optional' => ['posts/{id}/comments/{commentId?}']; |
|
48
|
|
|
yield 'complex path with mixed params' => ['api/v1/users/{userId}/posts/{postId}/comments/{commentId?}']; |
|
49
|
|
|
|
|
50
|
|
|
yield 'hyphens in path' => ['api-v2/user-profile']; |
|
51
|
|
|
yield 'underscores in path' => ['api_v2/user_profile']; |
|
52
|
|
|
yield 'numbers in path' => ['api/v123/users']; |
|
53
|
|
|
} |
|
54
|
|
|
|
|
55
|
|
|
public static function invalidPathProvider(): Generator |
|
56
|
|
|
{ |
|
57
|
|
|
yield 'empty string' => ['']; |
|
58
|
|
|
|
|
59
|
|
|
yield 'leading slash - simple' => ['/users']; |
|
60
|
|
|
yield 'leading slash - with segments' => ['/api/v1']; |
|
61
|
|
|
yield 'leading slash - single char' => ['/a']; |
|
62
|
|
|
yield 'leading slash - with param' => ['/{id}']; |
|
63
|
|
|
yield 'leading slash - with multiple segments' => ['/users/{id}']; |
|
64
|
|
|
|
|
65
|
|
|
yield 'trailing slash - simple' => ['users/']; |
|
66
|
|
|
yield 'trailing slash - multiple segments' => ['api/v1/']; |
|
67
|
|
|
yield 'trailing slash - single char' => ['a/']; |
|
68
|
|
|
yield 'trailing slash - with param' => ['{id}/']; |
|
69
|
|
|
yield 'trailing slash - with multiple segments' => ['users/{id}/']; |
|
70
|
|
|
|
|
71
|
|
|
yield 'double slash in middle' => ['users//posts']; |
|
72
|
|
|
yield 'multiple double slashes' => ['a//b//c']; |
|
73
|
|
|
yield 'double slash at end' => ['api//']; |
|
74
|
|
|
yield 'triple slash' => ['a///b']; |
|
75
|
|
|
yield 'simple double slash' => ['a//b']; |
|
76
|
|
|
yield 'double slash with more segments' => ['x//y//z']; |
|
77
|
|
|
|
|
78
|
|
|
yield 'mandatory after optional' => ['users/{id?}/{name}']; |
|
79
|
|
|
yield 'multiple optional then mandatory' => ['archive/{year?}/{month?}/{day}']; |
|
80
|
|
|
yield 'static after optional' => ['users/{id?}/posts']; |
|
81
|
|
|
yield 'static after multiple optional' => ['archive/{year?}/latest']; |
|
82
|
|
|
} |
|
83
|
|
|
} |
|
84
|
|
|
|