Merge "skin: Revert font-weight on successbox and move to preferences"
[lhc/web/wiklou.git] / tests / phpunit / includes / PathRouterTest.php
1 <?php
2 /**
3 * Tests for the PathRouter parsing
4 */
5
6 class PathRouterTest extends MediaWikiTestCase {
7
8 protected function setUp() {
9 parent::setUp();
10 $router = new PathRouter;
11 $router->add( "/wiki/$1" );
12 $this->basicRouter = $router;
13 }
14
15 /**
16 * Test basic path parsing
17 */
18 public function testBasic() {
19 $matches = $this->basicRouter->parse( "/wiki/Foo" );
20 $this->assertEquals( $matches, array( 'title' => "Foo" ) );
21 }
22
23 /**
24 * Test loose path auto-$1
25 */
26 public function testLoose() {
27 $router = new PathRouter;
28 $router->add( "/" ); # Should be the same as "/$1"
29 $matches = $router->parse( "/Foo" );
30 $this->assertEquals( $matches, array( 'title' => "Foo" ) );
31
32 $router = new PathRouter;
33 $router->add( "/wiki" ); # Should be the same as /wiki/$1
34 $matches = $router->parse( "/wiki/Foo" );
35 $this->assertEquals( $matches, array( 'title' => "Foo" ) );
36
37 $router = new PathRouter;
38 $router->add( "/wiki/" ); # Should be the same as /wiki/$1
39 $matches = $router->parse( "/wiki/Foo" );
40 $this->assertEquals( $matches, array( 'title' => "Foo" ) );
41 }
42
43 /**
44 * Test to ensure that path is based on specifity, not order
45 */
46 public function testOrder() {
47 $router = new PathRouter;
48 $router->add( "/$1" );
49 $router->add( "/a/$1" );
50 $router->add( "/b/$1" );
51 $matches = $router->parse( "/a/Foo" );
52 $this->assertEquals( $matches, array( 'title' => "Foo" ) );
53
54 $router = new PathRouter;
55 $router->add( "/b/$1" );
56 $router->add( "/a/$1" );
57 $router->add( "/$1" );
58 $matches = $router->parse( "/a/Foo" );
59 $this->assertEquals( $matches, array( 'title' => "Foo" ) );
60 }
61
62 /**
63 * Test the handling of key based arrays with a url parameter
64 */
65 public function testKeyParameter() {
66 $router = new PathRouter;
67 $router->add( array( 'edit' => "/edit/$1" ), array( 'action' => '$key' ) );
68 $matches = $router->parse( "/edit/Foo" );
69 $this->assertEquals( $matches, array( 'title' => "Foo", 'action' => 'edit' ) );
70 }
71
72 /**
73 * Test the handling of $2 inside paths
74 */
75 public function testAdditionalParameter() {
76 // Basic $2
77 $router = new PathRouter;
78 $router->add( '/$2/$1', array( 'test' => '$2' ) );
79 $matches = $router->parse( "/asdf/Foo" );
80 $this->assertEquals( $matches, array( 'title' => "Foo", 'test' => 'asdf' ) );
81 }
82
83 /**
84 * Test additional restricted value parameter
85 */
86 public function testRestrictedValue() {
87 $router = new PathRouter;
88 $router->add( '/$2/$1',
89 array( 'test' => '$2' ),
90 array( '$2' => array( 'a', 'b' ) )
91 );
92 $router->add( '/$2/$1',
93 array( 'test2' => '$2' ),
94 array( '$2' => 'c' )
95 );
96 $router->add( '/$1' );
97
98 $matches = $router->parse( "/asdf/Foo" );
99 $this->assertEquals( $matches, array( 'title' => "asdf/Foo" ) );
100
101 $matches = $router->parse( "/a/Foo" );
102 $this->assertEquals( $matches, array( 'title' => "Foo", 'test' => 'a' ) );
103
104 $matches = $router->parse( "/c/Foo" );
105 $this->assertEquals( $matches, array( 'title' => "Foo", 'test2' => 'c' ) );
106 }
107
108 public function callbackForTest( &$matches, $data ) {
109 $matches['x'] = $data['$1'];
110 $matches['foo'] = $data['foo'];
111 }
112
113 public function testCallback() {
114 $router = new PathRouter;
115 $router->add( "/$1",
116 array( 'a' => 'b', 'data:foo' => 'bar' ),
117 array( 'callback' => array( $this, 'callbackForTest' ) )
118 );
119 $matches = $router->parse( '/Foo' );
120 $this->assertEquals( $matches, array(
121 'title' => "Foo",
122 'x' => 'Foo',
123 'a' => 'b',
124 'foo' => 'bar'
125 ) );
126 }
127
128 /**
129 * Test to ensure that matches are not made if a parameter expects nonexistent input
130 */
131 public function testFail() {
132 $router = new PathRouter;
133 $router->add( "/wiki/$1", array( 'title' => "$1$2" ) );
134 $matches = $router->parse( "/wiki/A" );
135 $this->assertEquals( array(), $matches );
136 }
137
138 /**
139 * Test to ensure weight of paths is handled correctly
140 */
141 public function testWeight() {
142 $router = new PathRouter;
143 $router->addStrict( "/Bar", array( 'ping' => 'pong' ) );
144 $router->add( "/asdf-$1", array( 'title' => 'qwerty-$1' ) );
145 $router->add( "/$1" );
146 $router->add( "/qwerty-$1", array( 'title' => 'asdf-$1' ) );
147 $router->addStrict( "/Baz", array( 'marco' => 'polo' ) );
148 $router->add( "/a/$1" );
149 $router->add( "/asdf/$1" );
150 $router->add( "/$2/$1", array( 'unrestricted' => '$2' ) );
151 $router->add( array( 'qwerty' => "/qwerty/$1" ), array( 'qwerty' => '$key' ) );
152 $router->add( "/$2/$1", array( 'restricted-to-y' => '$2' ), array( '$2' => 'y' ) );
153
154 foreach (
155 array(
156 '/Foo' => array( 'title' => 'Foo' ),
157 '/Bar' => array( 'ping' => 'pong' ),
158 '/Baz' => array( 'marco' => 'polo' ),
159 '/asdf-foo' => array( 'title' => 'qwerty-foo' ),
160 '/qwerty-bar' => array( 'title' => 'asdf-bar' ),
161 '/a/Foo' => array( 'title' => 'Foo' ),
162 '/asdf/Foo' => array( 'title' => 'Foo' ),
163 '/qwerty/Foo' => array( 'title' => 'Foo', 'qwerty' => 'qwerty' ),
164 '/baz/Foo' => array( 'title' => 'Foo', 'unrestricted' => 'baz' ),
165 '/y/Foo' => array( 'title' => 'Foo', 'restricted-to-y' => 'y' ),
166 ) as $path => $result
167 ) {
168 $this->assertEquals( $router->parse( $path ), $result );
169 }
170 }
171
172 /**
173 * Make sure the router handles titles like Special:Recentchanges correctly
174 */
175 public function testSpecial() {
176 $matches = $this->basicRouter->parse( "/wiki/Special:Recentchanges" );
177 $this->assertEquals( $matches, array( 'title' => "Special:Recentchanges" ) );
178 }
179
180 /**
181 * Make sure the router decodes urlencoding properly
182 */
183 public function testUrlencoding() {
184 $matches = $this->basicRouter->parse( "/wiki/Title_With%20Space" );
185 $this->assertEquals( $matches, array( 'title' => "Title_With Space" ) );
186 }
187
188 public static function provideRegexpChars() {
189 return array(
190 array( "$" ),
191 array( "$1" ),
192 array( "\\" ),
193 array( "\\$1" ),
194 );
195 }
196
197 /**
198 * Make sure the router doesn't break on special characters like $ used in regexp replacements
199 * @dataProvider provideRegexpChars
200 */
201 public function testRegexpChars( $char ) {
202 $matches = $this->basicRouter->parse( "/wiki/$char" );
203 $this->assertEquals( $matches, array( 'title' => "$char" ) );
204 }
205
206 /**
207 * Make sure the router handles characters like +&() properly
208 */
209 public function testCharacters() {
210 $matches = $this->basicRouter->parse( "/wiki/Plus+And&Dollar\\Stuff();[]{}*" );
211 $this->assertEquals( $matches, array( 'title' => "Plus+And&Dollar\\Stuff();[]{}*" ) );
212 }
213
214 /**
215 * Make sure the router handles unicode characters correctly
216 * @depends testSpecial
217 * @depends testUrlencoding
218 * @depends testCharacters
219 */
220 public function testUnicode() {
221 $matches = $this->basicRouter->parse( "/wiki/Spécial:Modifications_récentes" );
222 $this->assertEquals( $matches, array( 'title' => "Spécial:Modifications_récentes" ) );
223
224 $matches = $this->basicRouter->parse( "/wiki/Sp%C3%A9cial:Modifications_r%C3%A9centes" );
225 $this->assertEquals( $matches, array( 'title' => "Spécial:Modifications_récentes" ) );
226 }
227
228 /**
229 * Ensure the router doesn't choke on long paths.
230 */
231 public function testLength() {
232 $matches = $this->basicRouter->parse( "/wiki/Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." );
233 $this->assertEquals( $matches, array( 'title' => "Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." ) );
234 }
235
236
237 /**
238 * Ensure that the php passed site of parameter values are not urldecoded
239 */
240 public function testPatternUrlencoding() {
241 $router = new PathRouter;
242 $router->add( "/wiki/$1", array( 'title' => '%20:$1' ) );
243 $matches = $router->parse( "/wiki/Foo" );
244 $this->assertEquals( $matches, array( 'title' => '%20:Foo' ) );
245 }
246
247 /**
248 * Ensure that raw parameter values do not have any variable replacements or urldecoding
249 */
250 public function testRawParamValue() {
251 $router = new PathRouter;
252 $router->add( "/wiki/$1", array( 'title' => array( 'value' => 'bar%20$1' ) ) );
253 $matches = $router->parse( "/wiki/Foo" );
254 $this->assertEquals( $matches, array( 'title' => 'bar%20$1' ) );
255 }
256 }