wfProfileOut() for new return added in c6396 (c4e407c)
[lhc/web/wiklou.git] / tests / qunit / suites / resources / mediawiki / mediawiki.Uri.test.js
1 module( 'mediawiki.Uri', QUnit.newMwEnvironment() );
2
3 test( '-- Initial check', function () {
4 expect( 2 );
5
6 // Ensure we have a generic URI parser if not running in a browser
7 if ( !mw.Uri ) {
8 mw.Uri = mw.UriRelative( 'http://example.com/' );
9 }
10
11 ok( mw.UriRelative, 'mw.UriRelative defined' );
12 ok( mw.Uri, 'mw.Uri defined' );
13 } );
14
15 $.each( [true, false], function ( i, strictMode ) {
16 test( 'Basic mw.Uri object test in ' + ( strictMode ? '' : 'non-' ) + 'strict mode for a simple HTTP URI', function () {
17 var uriString, uri;
18 expect( 2 );
19
20 uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
21 uri = new mw.Uri( uriString, {
22 strictMode: strictMode
23 });
24
25 deepEqual(
26 {
27 protocol: uri.protocol,
28 host: uri.host,
29 port: uri.port,
30 path: uri.path,
31 query: uri.query,
32 fragment: uri.fragment
33 }, {
34 protocol: 'http',
35 host: 'www.ietf.org',
36 port: undefined,
37 path: '/rfc/rfc2396.txt',
38 query: {},
39 fragment: undefined
40 },
41 'basic object properties'
42 );
43
44 deepEqual(
45 {
46 userInfo: uri.getUserInfo(),
47 authority: uri.getAuthority(),
48 hostPort: uri.getHostPort(),
49 queryString: uri.getQueryString(),
50 relativePath: uri.getRelativePath(),
51 toString: uri.toString()
52 },
53 {
54 userInfo: '',
55 authority: 'www.ietf.org',
56 hostPort: 'www.ietf.org',
57 queryString: '',
58 relativePath: '/rfc/rfc2396.txt',
59 toString: uriString
60 },
61 'construct composite components of URI on request'
62 );
63
64 });
65 });
66
67 test( 'Parse an ftp URI correctly with user and password', function () {
68 var uri;
69 expect( 1 );
70
71 uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
72
73 deepEqual(
74 {
75 protocol: uri.protocol,
76 user: uri.user,
77 password: uri.password,
78 host: uri.host,
79 port: uri.port,
80 path: uri.path,
81 query: uri.query,
82 fragment: uri.fragment
83 },
84 {
85 protocol: 'ftp',
86 user: 'usr',
87 password: 'pwd',
88 host: '192.0.2.16',
89 port: undefined,
90 path: '/',
91 query: {},
92 fragment: undefined
93 },
94 'basic object properties'
95 );
96 } );
97
98 test( 'Parse a uri with simple querystring', function () {
99 var uri;
100 expect( 1 );
101
102 uri = new mw.Uri( 'http://www.google.com/?q=uri' );
103
104 deepEqual(
105 {
106 protocol: uri.protocol,
107 host: uri.host,
108 port: uri.port,
109 path: uri.path,
110 query: uri.query,
111 fragment: uri.fragment,
112 queryString: uri.getQueryString()
113 },
114 {
115 protocol: 'http',
116 host: 'www.google.com',
117 port: undefined,
118 path: '/',
119 query: { q: 'uri' },
120 fragment: undefined,
121 queryString: 'q=uri'
122 },
123 'basic object properties'
124 );
125 } );
126
127 test( 'Handle multiple query parameter (overrideKeys on)', function () {
128 var uri;
129 expect( 5 );
130
131 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
132 overrideKeys: true
133 });
134
135 equal( uri.query.n, '1', 'multiple parameters are parsed' );
136 equal( uri.query.m, 'bar', 'last key overrides earlier keys' );
137
138 uri.query.n = [ 'x', 'y', 'z' ];
139
140 // Verify parts and total length instead of entire string because order
141 // of iteration can vary.
142 ok( uri.toString().indexOf( 'm=bar' ), 'toString preserves other values' );
143 ok( uri.toString().indexOf( 'n=x&n=y&n=z' ), 'toString parameter includes all values of an array query parameter' );
144 equal( uri.toString().length, 'http://www.example.com/dir/?m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
145 } );
146
147 test( 'Handle multiple query parameter (overrideKeys off)', function () {
148 var uri;
149 expect( 9 );
150
151 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
152 overrideKeys: false
153 });
154
155 // Strict comparison so that types are also verified (n should be string '1')
156 strictEqual( uri.query.m.length, 2, 'multi-value query should be an array with 2 items' );
157 strictEqual( uri.query.m[0], 'foo', 'order and value is correct' );
158 strictEqual( uri.query.m[1], 'bar', 'order and value is correct' );
159 strictEqual( uri.query.n, '1', 'n=1 is parsed with the correct value of the expected type' );
160
161 // Change query values
162 uri.query.n = [ 'x', 'y', 'z' ];
163
164 // Verify parts and total length instead of entire string because order
165 // of iteration can vary.
166 ok( uri.toString().indexOf( 'm=foo&m=bar' ) >= 0, 'toString preserves other values' );
167 ok( uri.toString().indexOf( 'n=x&n=y&n=z' ) >= 0, 'toString parameter includes all values of an array query parameter' );
168 equal( uri.toString().length, 'http://www.example.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
169
170 // Remove query values
171 uri.query.m.splice( 0, 1 );
172 delete uri.query.n;
173
174 equal( uri.toString(), 'http://www.example.com/dir/?m=bar', 'deletion properties' );
175
176 // Remove more query values, leaving an empty array
177 uri.query.m.splice( 0, 1 );
178 equal( uri.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
179 } );
180
181 test( 'All-dressed URI with everything', function () {
182 var uri, queryString, relativePath;
183 expect( 11 );
184
185 uri = new mw.Uri( 'http://auth@www.example.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
186
187 deepEqual(
188 {
189 protocol: uri.protocol,
190 user: uri.user,
191 password: uri.password,
192 host: uri.host,
193 port: uri.port,
194 path: uri.path,
195 query: uri.query,
196 fragment: uri.fragment
197 },
198 {
199 protocol: 'http',
200 user: 'auth',
201 password: undefined,
202 host: 'www.example.com',
203 port: '81',
204 path: '/dir/dir.2/index.htm',
205 query: { q1: '0', test1: null, test2: 'value (escaped)' },
206 fragment: 'top'
207 },
208 'basic object properties'
209 );
210
211 equal( uri.getUserInfo(), 'auth', 'user info' );
212
213 equal( uri.getAuthority(), 'auth@www.example.com:81', 'authority equal to auth@hostport' );
214
215 equal( uri.getHostPort(), 'www.example.com:81', 'hostport equal to host:port' );
216
217 queryString = uri.getQueryString();
218 ok( queryString.indexOf( 'q1=0' ) >= 0, 'query param with numbers' );
219 ok( queryString.indexOf( 'test1' ) >= 0, 'query param with null value is included' );
220 ok( queryString.indexOf( 'test1=' ) === -1, 'query param with null value does not generate equals sign' );
221 ok( queryString.indexOf( 'test2=value+%28escaped%29' ) >= 0, 'query param is url escaped' );
222
223 relativePath = uri.getRelativePath();
224 ok( relativePath.indexOf( uri.path ) >= 0, 'path in relative path' );
225 ok( relativePath.indexOf( uri.getQueryString() ) >= 0, 'query string in relative path' );
226 ok( relativePath.indexOf( uri.fragment ) >= 0, 'fragement in relative path' );
227 } );
228
229 test( 'Cloning', function () {
230 var original, clone;
231 expect( 5 );
232
233 original = new mw.Uri( 'http://en.wiki.local/w/api.php?action=query&foo=bar' );
234 clone = original.clone();
235
236 deepEqual( clone, original, 'clone has equivalent properties' );
237 equal( original.toString(), clone.toString(), 'toString matches original' );
238
239 notStrictEqual( clone, original, 'clone is not the same when compared by reference' );
240
241 clone.host = 'fr.wiki.local';
242 notEqual( original.host, clone.host, 'manipulating clone did not effect original' );
243 notEqual( original.toString(), clone.toString(), 'toString no longer matches original' );
244 } );
245
246 test( 'Constructing mw.Uri from plain object', function () {
247 var uri;
248 expect( 3 );
249
250 uri = new mw.Uri({
251 protocol: 'http',
252 host: 'www.foo.local',
253 path: '/this'
254 });
255 equal( uri.toString(), 'http://www.foo.local/this', 'Basic properties' );
256
257 uri = new mw.Uri({
258 protocol: 'http',
259 host: 'www.foo.local',
260 path: '/this',
261 query: { hi: 'there' },
262 fragment: 'blah'
263 });
264 equal( uri.toString(), 'http://www.foo.local/this?hi=there#blah', 'More complex properties' );
265
266 raises(
267 function () {
268 var uri = new mw.Uri({
269 protocol: 'http',
270 host: 'www.foo.local'
271 });
272 },
273 function ( e ) {
274 return e.message === 'Bad constructor arguments';
275 },
276 'Construction failed when missing required properties'
277 );
278 } );
279
280 test( 'Manipulate properties', function () {
281 var uriBase, uri;
282 expect( 8 );
283
284 uriBase = new mw.Uri( 'http://en.wiki.local/w/api.php' );
285
286 uri = uriBase.clone();
287 uri.fragment = 'frag';
288 equal( uri.toString(), 'http://en.wiki.local/w/api.php#frag', 'add a fragment' );
289
290 uri = uriBase.clone();
291 uri.host = 'fr.wiki.local';
292 uri.port = '8080';
293 equal( uri.toString(), 'http://fr.wiki.local:8080/w/api.php', 'change host and port' );
294
295 uri = uriBase.clone();
296 uri.query.foo = 'bar';
297 equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'add query arguments' );
298
299 delete uri.query.foo;
300 equal( uri.toString(), 'http://en.wiki.local/w/api.php', 'delete query arguments' );
301
302 uri = uriBase.clone();
303 uri.query.foo = 'bar';
304 equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'extend query arguments' );
305 uri.extend({
306 foo: 'quux',
307 pif: 'paf'
308 });
309 ok( uri.toString().indexOf( 'foo=quux' ) >= 0, 'extend query arguments' );
310 ok( uri.toString().indexOf( 'foo=bar' ) === -1, 'extend query arguments' );
311 ok( uri.toString().indexOf( 'pif=paf' ) >= 0 , 'extend query arguments' );
312 } );
313
314 test( 'Handle protocol-relative URLs', function () {
315 var UriRel, uri;
316 expect( 5 );
317
318 UriRel = mw.UriRelative( 'glork://en.wiki.local/foo.php' );
319
320 uri = new UriRel( '//en.wiki.local/w/api.php' );
321 equal( uri.protocol, 'glork', 'create protocol-relative URLs with same protocol as document' );
322
323 uri = new UriRel( '/foo.com' );
324 equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in loose mode' );
325
326 uri = new UriRel( 'http:/foo.com' );
327 equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in loose mode' );
328
329 uri = new UriRel( '/foo.com', true );
330 equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in strict mode' );
331
332 uri = new UriRel( 'http:/foo.com', true );
333 equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in strict mode' );
334 } );
335
336 test( 'Bad calls', function () {
337 var uri;
338 expect( 5 );
339
340 raises(
341 function () {
342 new mw.Uri();
343 },
344 function ( e ) {
345 return e.message === 'Bad constructor arguments';
346 },
347 'throw error on no arguments to constructor'
348 );
349
350 raises(
351 function () {
352 new mw.Uri( '' );
353 },
354 function ( e ) {
355 return e.message === 'Bad constructor arguments';
356 },
357 'throw error on empty string as argument to constructor'
358 );
359
360 raises(
361 function () {
362 new mw.Uri( 'glaswegian penguins' );
363 },
364 function ( e ) {
365 return e.message === 'Bad constructor arguments';
366 },
367 'throw error on non-URI as argument to constructor'
368 );
369
370 raises(
371 function () {
372 new mw.Uri( 'foo.com/bar/baz', {
373 strictMode: true
374 });
375 },
376 function ( e ) {
377 return e.message === 'Bad constructor arguments';
378 },
379 'throw error on URI without protocol or // or leading / in strict mode'
380 );
381
382 uri = new mw.Uri( 'foo.com/bar/baz', {
383 strictMode: false
384 });
385 equal( uri.toString(), 'http://foo.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
386 });
387
388 test( 'bug 35658', function () {
389 expect( 2 );
390
391 var testProtocol, testServer, testPort, testPath, UriClass, uri, href;
392
393 testProtocol = 'https://';
394 testServer = 'foo.example.org';
395 testPort = '3004';
396 testPath = '/!1qy';
397
398 UriClass = mw.UriRelative( testProtocol + testServer + '/some/path/index.html' );
399 uri = new UriClass( testPath );
400 href = uri.toString();
401 equal( href, testProtocol + testServer + testPath, 'Root-relative URL gets host & protocol supplied' );
402
403 UriClass = mw.UriRelative( testProtocol + testServer + ':' + testPort + '/some/path.php' );
404 uri = new UriClass( testPath );
405 href = uri.toString();
406 equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' );
407
408 } );