4 * Tests for the PathRouter parsing.
8 class PathRouterTest
extends MediaWikiTestCase
{
13 protected $basicRouter;
15 protected function setUp() {
17 $router = new PathRouter
;
18 $router->add( "/wiki/$1" );
19 $this->basicRouter
= $router;
22 public static function provideParse() {
25 'Basic path parsing' => [
31 'Loose path auto-$1: /$1' => [
36 'Loose path auto-$1: /wiki' => [
41 'Loose path auto-$1: /wiki/' => [
46 // Ensure that path is based on specificity, not order
47 'Order, /$1 added first' => [
48 [ "/$1", "/a/$1", "/b/$1" ],
52 'Order, /$1 added last' => [
53 [ "/b/$1", "/a/$1", "/$1" ],
57 // Handling of key based arrays with a url parameter
58 'Key based array' => [
60 'path' => [ 'edit' => "/edit/$1" ],
61 'params' => [ 'action' => '$key' ],
64 [ 'title' => "Foo", 'action' => 'edit' ]
66 // Additional parameter
70 'params' => [ 'test' => '$2' ]
73 [ 'title' => "Foo", 'test' => 'asdf' ]
76 // Shared patterns for restricted value parameter tests
77 $restrictedPatterns = [
80 'params' => [ 'test' => '$2' ],
81 'options' => [ '$2' => [ 'a', 'b' ] ]
85 'params' => [ 'test2' => '$2' ],
86 'options' => [ '$2' => 'c' ]
91 // Restricted value parameter tests
95 [ 'title' => "asdf/Foo" ]
100 [ 'title' => "Foo", 'test' => 'a' ]
105 [ 'title' => "Foo", 'test2' => 'c' ]
112 'params' => [ 'a' => 'b', 'data:foo' => 'bar' ],
113 'options' => [ 'callback' => [ __CLASS__
, 'callbackForTest' ] ]
124 // Test to ensure that matches are not made if a parameter expects nonexistent input
127 'path' => "/wiki/$1",
128 'params' => [ 'title' => "$1$2" ],
134 // Make sure the router handles titles like Special:Recentchanges correctly
137 "/wiki/Special:Recentchanges",
138 [ 'title' => "Special:Recentchanges" ]
141 // Make sure the router decodes urlencoding properly
144 "/wiki/Title_With%20Space",
145 [ 'title' => "Title_With Space" ]
150 // Make sure the router doesn't break on special characters like $ used in regexp replacements
151 foreach ( [ "$", "$1", "\\", "\\$1" ] as $char ) {
152 $tests["Regexp character $char"] = [
155 [ 'title' => "$char" ]
160 // Make sure the router handles characters like +&() properly
161 "Special characters" => [
163 "/wiki/Plus+And&Dollar\\Stuff();[]{}*",
164 [ 'title' => "Plus+And&Dollar\\Stuff();[]{}*" ],
167 // Make sure the router handles unicode characters correctly
170 "/wiki/Spécial:Modifications_récentes" ,
171 [ 'title' => "Spécial:Modifications_récentes" ],
176 "/wiki/Sp%C3%A9cial:Modifications_r%C3%A9centes",
177 [ 'title' => "Spécial:Modifications_récentes" ],
181 // Ensure the router doesn't choke on long paths.
182 $lorem = "Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_" .
183 "tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_" .
184 "nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._" .
185 "Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_" .
186 "eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_" .
187 "in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum.";
193 [ 'title' => $lorem ]
196 // Ensure that the php passed site of parameter values are not urldecoded
197 "Pattern urlencoding" => [
198 [ [ 'path' => "/wiki/$1", 'params' => [ 'title' => '%20:$1' ] ] ],
200 [ 'title' => '%20:Foo' ]
203 // Ensure that raw parameter values do not have any variable replacements or urldecoding
204 "Raw param value" => [
205 [ [ 'path' => "/wiki/$1", 'params' => [ 'title' => [ 'value' => 'bar%20$1' ] ] ] ],
207 [ 'title' => 'bar%20$1' ]
216 * @dataProvider provideParse
218 public function testParse( $patterns, $path, $expected ) {
219 $patterns = (array)$patterns;
221 $router = new PathRouter
;
222 foreach ( $patterns as $pattern ) {
223 if ( is_array( $pattern ) ) {
224 $router->add( $pattern['path'], $pattern['params'] ??
[],
225 $pattern['options'] ??
[] );
227 $router->add( $pattern );
230 $matches = $router->parse( $path );
231 $this->assertEquals( $matches, $expected );
234 public static function callbackForTest( &$matches, $data ) {
235 $matches['x'] = $data['$1'];
236 $matches['foo'] = $data['foo'];
239 public static function provideWeight() {
241 [ '/Foo', [ 'title' => 'Foo' ] ],
242 [ '/Bar', [ 'ping' => 'pong' ] ],
243 [ '/Baz', [ 'marco' => 'polo' ] ],
244 [ '/asdf-foo', [ 'title' => 'qwerty-foo' ] ],
245 [ '/qwerty-bar', [ 'title' => 'asdf-bar' ] ],
246 [ '/a/Foo', [ 'title' => 'Foo' ] ],
247 [ '/asdf/Foo', [ 'title' => 'Foo' ] ],
248 [ '/qwerty/Foo', [ 'title' => 'Foo', 'qwerty' => 'qwerty' ] ],
249 [ '/baz/Foo', [ 'title' => 'Foo', 'unrestricted' => 'baz' ] ],
250 [ '/y/Foo', [ 'title' => 'Foo', 'restricted-to-y' => 'y' ] ],
255 * Test to ensure weight of paths is handled correctly
256 * @dataProvider provideWeight
258 public function testWeight( $path, $expected ) {
259 $router = new PathRouter
;
260 $router->addStrict( "/Bar", [ 'ping' => 'pong' ] );
261 $router->add( "/asdf-$1", [ 'title' => 'qwerty-$1' ] );
262 $router->add( "/$1" );
263 $router->add( "/qwerty-$1", [ 'title' => 'asdf-$1' ] );
264 $router->addStrict( "/Baz", [ 'marco' => 'polo' ] );
265 $router->add( "/a/$1" );
266 $router->add( "/asdf/$1" );
267 $router->add( "/$2/$1", [ 'unrestricted' => '$2' ] );
268 $router->add( [ 'qwerty' => "/qwerty/$1" ], [ 'qwerty' => '$key' ] );
269 $router->add( "/$2/$1", [ 'restricted-to-y' => '$2' ], [ '$2' => 'y' ] );
271 $this->assertEquals( $router->parse( $path ), $expected );