‪TYPO3CMS  ‪main
RouteSorterTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
24 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
25 
26 final class ‪RouteSorterTest extends UnitTestCase
27 {
28  public static function ‪routesAreSortedForGenerationDataProvider(): array
29  {
30  return [
31  'default route only' => [
32  // routes
33  [
34  ‪self::createDefaultRoute('/default'),
35  ],
36  // given parameters
37  [],
38  // expected route paths order
39  [
40  '/default',
41  ],
42  ],
43  'static, default route' => [
44  [
45  ‪self::createDefaultRoute('/default-1'),
46  ‪self::createRoute('/list'),
47  ‪self::createDefaultRoute('/default-2'),
48  ],
49  [],
50  [
51  '/list',
52  '/default-1',
53  '/default-2',
54  ],
55  ],
56  'mandatory, static, default route' => [
57  [
58  ‪self::createDefaultRoute('/default'),
59  ‪self::createRoute('/list'),
60  ‪self::createRoute('/list/{page}', ['page' => 0]),
61  ],
62  [],
63  [
64  '/list/{page}',
65  '/list',
66  '/default',
67  ],
68  ],
69  // not really important, since missing mandatory
70  // variables would have been skipped during generation
71  'ambiguous routes, no parameters, most probable' => [
72  [
73  ‪self::createRoute('/list'),
74  ‪self::createRoute('/list/{uid}'),
75  ‪self::createRoute('/list/{uid}/{category}', ['category' => 0]),
76  ‪self::createRoute('/list/{page}', ['page' => 0]),
77  ‪self::createRoute('/list/{category}', ['category' => 0]),
78  ],
79  [],
80  [
81  '/list/{page}', // no parameters given -> defaults take precedence
82  '/list/{category}', // no parameters given -> defaults take precedence
83  '/list/{uid}',
84  '/list/{uid}/{category}',
85  '/list',
86  ],
87  ],
88  'mandatory first, ambiguous parameters' => [
89  [
90  ‪self::createRoute('/list'),
91  ‪self::createRoute('/list/{uid}'),
92  ‪self::createRoute('/list/{uid}/{category}', ['category' => 0]),
93  ‪self::createRoute('/list/{page}', ['page' => 0]),
94  ‪self::createRoute('/list/{category}', ['category' => 0]),
95  ],
96  [
97  'uid' => 123,
98  'page' => 1,
99  ],
100  [
101  '/list/{uid}', // value for {uid} given, complete mandatory first -> takes precedence
102  '/list/{page}', // value for {page} given, complete first -> takes precedence
103  '/list/{uid}/{category}',
104  '/list/{category}',
105  '/list',
106  ],
107  ],
108  'complete first, ambiguous parameters #1' => [
109  [
110  ‪self::createRoute('/list'),
111  ‪self::createRoute('/list/{uid}'),
112  ‪self::createRoute('/list/{uid}/{category}', ['category' => 0]),
113  ‪self::createRoute('/list/{page}', ['page' => 0]),
114  ‪self::createRoute('/list/{category}', ['category' => 0]),
115  ],
116  [
117  'category' => 1,
118  'page' => 1,
119  ],
120  [
121  '/list/{page}', // value for default {page} given, complete first -> takes precedence
122  '/list/{category}',
123  '/list/{uid}',
124  '/list/{uid}/{category}',
125  '/list',
126  ],
127  ],
128  'complete first, ambiguous parameters #2' => [
129  [
130  ‪self::createRoute('/list'),
131  ‪self::createRoute('/list/{uid}'),
132  ‪self::createRoute('/list/{uid}/{category}', ['category' => 0]),
133  ‪self::createRoute('/list/{page}', ['page' => 0]),
134  ‪self::createRoute('/list/{category}', ['category' => 0]),
135  ],
136  [
137  'uid' => 123,
138  'page' => 1,
139  'category' => 2,
140  ],
141  [
142  '/list/{uid}/{category}', // values for {uid} and {category} given, complete first -> takes precedence
143  '/list/{uid}',
144  '/list/{page}',
145  '/list/{category}',
146  '/list',
147  ],
148  ],
149  // not really important, just to show order is kept
150  'defaults only, no parameters given #1' => [
151  [
152  ‪self::createRoute('/list/{defA}/{defB}/{defC}', ['defA' => 0, 'defB' => 0, 'defC' => 0]),
153  ‪self::createRoute('/list/{defD}/{defE}/{defF}', ['defD' => 0, 'defE' => 0, 'defF' => 0]),
154  ],
155  [
156  ],
157  [
158  '/list/{defA}/{defB}/{defC}',
159  '/list/{defD}/{defE}/{defF}',
160  ],
161  ],
162  // not really important, just to show order is kept
163  'defaults only, no parameters given #2' => [
164  [
165  ‪self::createRoute('/list/{defD}/{defE}/{defF}', ['defD' => 0, 'defE' => 0, 'defF' => 0]),
166  ‪self::createRoute('/list/{defA}/{defB}/{defC}', ['defA' => 0, 'defB' => 0, 'defC' => 0]),
167  ],
168  [
169  ],
170  [
171  '/list/{defD}/{defE}/{defF}',
172  '/list/{defA}/{defB}/{defC}',
173  ],
174  ],
175  'defaults only, {defF} given, best match' => [
176  [
177  ‪self::createRoute('/list/{defA}/{defB}/{defC}', ['defA' => 0, 'defB' => 0, 'defC' => 0]),
178  ‪self::createRoute('/list/{defD}/{defE}/{defF}', ['defD' => 0, 'defE' => 0, 'defF' => 0]),
179  ],
180  [
181  'defF' => 1,
182  ],
183  [
184  '/list/{defD}/{defE}/{defF}', // {defF} given, best match -> takes precedence
185  '/list/{defA}/{defB}/{defC}',
186  ],
187  ],
188  'mixed variables, ambiguous parameters, complete mandatory first #1' => [
189  [
190  ‪self::createRoute('/list/{d}/{e}/{defF}', ['defF' => 0]),
191  ‪self::createRoute('/list/{a}/{defB}/{defC}', ['defB' => 0, 'defC' => 0]),
192  ],
193  [
194  'a' => 1,
195  'd' => 1,
196  'defF' => 1,
197  ],
198  [
199  '/list/{a}/{defB}/{defC}', // mandatory {a} given, complete mandatory first -> takes precedence
200  '/list/{d}/{e}/{defF}',
201  ],
202  ],
203  'mixed variables, ambiguous parameters, complete mandatory first #2' => [
204  [
205  ‪self::createRoute('/list/{a}/{defB}/{defC}', ['defB' => 0, 'defC' => 0]),
206  ‪self::createRoute('/list/{d}/{e}/{defF}', ['defF' => 0]),
207  ],
208  [
209  'd' => 1,
210  'e' => 1,
211  'defB' => 1,
212  'defC' => 1,
213  ],
214  [
215  '/list/{d}/{e}/{defF}', // mandatory {d} and {e} given, complete mandatory first -> takes precedence
216  '/list/{a}/{defB}/{defC}',
217  ],
218  ],
219  'mixed variables, ambiguous parameters, complete first' => [
220  [
221  ‪self::createRoute('/list/{d}/{e}/{defF}', ['defF' => 0]),
222  ‪self::createRoute('/list/{a}/{defB}/{defC}', ['defB' => 0, 'defC' => 0]),
223  ],
224  [
225  'd' => 1,
226  'e' => 1,
227  'a' => 1,
228  'defB' => 1,
229  'defC' => 1,
230  ],
231  [
232  '/list/{a}/{defB}/{defC}', // all parameters given, complete first -> takes precedence
233  '/list/{d}/{e}/{defF}',
234  ],
235  ],
236  ];
237  }
238 
244  #[DataProvider('routesAreSortedForGenerationDataProvider')]
245  #[Test]
246  public function ‪routesAreSortedForGeneration(array $givenRoutes, array $givenParameters, array $expectation): void
247  {
248  $sorter = (new ‪RouteSorter())
249  ->withRoutes($givenRoutes)
250  ->withOriginalParameters($givenParameters);
251  $routes = $sorter->sortRoutesForGeneration()->getRoutes();
252  $routePaths = array_map([$this, 'getRoutePath'], array_values($routes));
253  self::assertSame($expectation, $routePaths);
254  }
255 
256  private function ‪getRoutePath(‪Route $route): string
257  {
258  return $route->getPath();
259  }
260 
261  private static function ‪createRoute(string $path, array $defaults = []): ‪Route
262  {
263  $route = new ‪Route($path);
264  $route->setDefaults($defaults);
265  return $route;
266  }
267 
268  private static function ‪createDefaultRoute(string $path): ‪Route
269  {
270  $route = new ‪Route($path);
271  $route->setOption('_isDefault', true);
272  return $route;
273  }
274 }
‪TYPO3\CMS\Core\Tests\Unit\Routing\RouteSorterTest\createRoute
‪static createRoute(string $path, array $defaults=[])
Definition: RouteSorterTest.php:261
‪TYPO3\CMS\Core\Tests\Unit\Routing
‪TYPO3\CMS\Core\Tests\Unit\Routing\RouteSorterTest\createDefaultRoute
‪static createDefaultRoute(string $path)
Definition: RouteSorterTest.php:268
‪TYPO3\CMS\Core\Tests\Unit\Routing\RouteSorterTest\getRoutePath
‪getRoutePath(Route $route)
Definition: RouteSorterTest.php:256
‪TYPO3\CMS\Core\Tests\Unit\Routing\RouteSorterTest
Definition: RouteSorterTest.php:27
‪TYPO3\CMS\Core\Tests\Unit\Routing\RouteSorterTest\routesAreSortedForGenerationDataProvider
‪static routesAreSortedForGenerationDataProvider()
Definition: RouteSorterTest.php:28
‪TYPO3\CMS\Core\Tests\Unit\Routing\RouteSorterTest\routesAreSortedForGeneration
‪routesAreSortedForGeneration(array $givenRoutes, array $givenParameters, array $expectation)
Definition: RouteSorterTest.php:246
‪TYPO3\CMS\Core\Routing\Route
Definition: Route.php:32
‪TYPO3\CMS\Core\Routing\RouteSorter
Definition: RouteSorter.php:25