Add a 'revdelete-selected-file' message on Special:RevisionDelete
[lhc/web/wiklou.git] / tests / qunit / suites / resources / mediawiki / mediawiki.Title.test.js
1 ( function ( mw, $ ) {
2 // mw.Title relies on these three config vars
3 // Restore them after each test run
4 var config = {
5 wgFormattedNamespaces: {
6 '-2': 'Media',
7 '-1': 'Special',
8 0: '',
9 1: 'Talk',
10 2: 'User',
11 3: 'User talk',
12 4: 'Wikipedia',
13 5: 'Wikipedia talk',
14 6: 'File',
15 7: 'File talk',
16 8: 'MediaWiki',
17 9: 'MediaWiki talk',
18 10: 'Template',
19 11: 'Template talk',
20 12: 'Help',
21 13: 'Help talk',
22 14: 'Category',
23 15: 'Category talk',
24 // testing custom / localized namespace
25 100: 'Penguins'
26 },
27 wgNamespaceIds: {
28 /*jshint camelcase: false */
29 media: -2,
30 special: -1,
31 '': 0,
32 talk: 1,
33 user: 2,
34 user_talk: 3,
35 wikipedia: 4,
36 wikipedia_talk: 5,
37 file: 6,
38 file_talk: 7,
39 mediawiki: 8,
40 mediawiki_talk: 9,
41 template: 10,
42 template_talk: 11,
43 help: 12,
44 help_talk: 13,
45 category: 14,
46 category_talk: 15,
47 image: 6,
48 image_talk: 7,
49 project: 4,
50 project_talk: 5,
51 /* testing custom / alias */
52 penguins: 100,
53 antarctic_waterfowl: 100
54 },
55 wgCaseSensitiveNamespaces: []
56 },
57 repeat = function ( input, multiplier ) {
58 return new Array( multiplier + 1 ).join( input );
59 },
60 cases = {
61 // See also TitleTest.php#testSecureAndSplit
62 valid: [
63 'Sandbox',
64 'A "B"',
65 'A \'B\'',
66 '.com',
67 '~',
68 '"',
69 '\'',
70 'Talk:Sandbox',
71 'Talk:Foo:Sandbox',
72 'File:Example.svg',
73 'File_talk:Example.svg',
74 'Foo/.../Sandbox',
75 'Sandbox/...',
76 'A~~',
77 // Length is 256 total, but only title part matters
78 'Category:' + repeat( 'x', 248 ),
79 repeat( 'x', 252 )
80 ],
81 invalid: [
82 '',
83 ':',
84 '__ __',
85 ' __ ',
86 // Bad characters forbidden regardless of wgLegalTitleChars
87 'A [ B',
88 'A ] B',
89 'A { B',
90 'A } B',
91 'A < B',
92 'A > B',
93 'A | B',
94 // URL encoding
95 'A%20B',
96 'A%23B',
97 'A%2523B',
98 // XML/HTML character entity references
99 // Note: The ones with # are commented out as those are interpreted as fragment and
100 // as such end up being valid.
101 'A &eacute; B',
102 //'A &#233; B',
103 //'A &#x00E9; B',
104 // Subject of NS_TALK does not roundtrip to NS_MAIN
105 'Talk:File:Example.svg',
106 // Directory navigation
107 '.',
108 '..',
109 './Sandbox',
110 '../Sandbox',
111 'Foo/./Sandbox',
112 'Foo/../Sandbox',
113 'Sandbox/.',
114 'Sandbox/..',
115 // Tilde
116 'A ~~~ Name',
117 'A ~~~~ Signature',
118 'A ~~~~~ Timestamp',
119 repeat( 'x', 256 ),
120 // Extension separation is a js invention, for length
121 // purposes it is part of the title
122 repeat( 'x', 252 ) + '.json',
123 // Namespace prefix without actual title
124 'Talk:',
125 'Category: ',
126 'Category: #bar'
127 ]
128 };
129
130 QUnit.module( 'mediawiki.Title', QUnit.newMwEnvironment( { config: config } ) );
131
132 QUnit.test( 'constructor', cases.invalid.length, function ( assert ) {
133 var i, title;
134 for ( i = 0; i < cases.valid.length; i++ ) {
135 title = new mw.Title( cases.valid[i] );
136 }
137 for ( i = 0; i < cases.invalid.length; i++ ) {
138 /*jshint loopfunc:true */
139 title = cases.invalid[i];
140 assert.throws( function () {
141 return new mw.Title( title );
142 }, cases.invalid[i] );
143 }
144 } );
145
146 QUnit.test( 'newFromText', cases.valid.length + cases.invalid.length, function ( assert ) {
147 var i;
148 for ( i = 0; i < cases.valid.length; i++ ) {
149 assert.equal(
150 $.type( mw.Title.newFromText( cases.valid[i] ) ),
151 'object',
152 cases.valid[i]
153 );
154 }
155 for ( i = 0; i < cases.invalid.length; i++ ) {
156 assert.equal(
157 $.type( mw.Title.newFromText( cases.invalid[i] ) ),
158 'null',
159 cases.invalid[i]
160 );
161 }
162 } );
163
164 QUnit.test( 'Basic parsing', 12, function ( assert ) {
165 var title;
166 title = new mw.Title( 'File:Foo_bar.JPG' );
167
168 assert.equal( title.getNamespaceId(), 6 );
169 assert.equal( title.getNamespacePrefix(), 'File:' );
170 assert.equal( title.getName(), 'Foo_bar' );
171 assert.equal( title.getNameText(), 'Foo bar' );
172 assert.equal( title.getExtension(), 'JPG' );
173 assert.equal( title.getDotExtension(), '.JPG' );
174 assert.equal( title.getMain(), 'Foo_bar.JPG' );
175 assert.equal( title.getMainText(), 'Foo bar.JPG' );
176 assert.equal( title.getPrefixedDb(), 'File:Foo_bar.JPG' );
177 assert.equal( title.getPrefixedText(), 'File:Foo bar.JPG' );
178
179 title = new mw.Title( 'Foo#bar' );
180 assert.equal( title.getPrefixedText(), 'Foo' );
181 assert.equal( title.getFragment(), 'bar' );
182 } );
183
184 QUnit.test( 'Transformation', 11, function ( assert ) {
185 var title;
186
187 title = new mw.Title( 'File:quux pif.jpg' );
188 assert.equal( title.getNameText(), 'Quux pif', 'First character of title' );
189
190 title = new mw.Title( 'File:Glarg_foo_glang.jpg' );
191 assert.equal( title.getNameText(), 'Glarg foo glang', 'Underscores' );
192
193 title = new mw.Title( 'User:ABC.DEF' );
194 assert.equal( title.toText(), 'User:ABC.DEF', 'Round trip text' );
195 assert.equal( title.getNamespaceId(), 2, 'Parse canonical namespace prefix' );
196
197 title = new mw.Title( 'Image:quux pix.jpg' );
198 assert.equal( title.getNamespacePrefix(), 'File:', 'Transform alias to canonical namespace' );
199
200 title = new mw.Title( 'uSEr:hAshAr' );
201 assert.equal( title.toText(), 'User:HAshAr' );
202 assert.equal( title.getNamespaceId(), 2, 'Case-insensitive namespace prefix' );
203
204 // Don't ask why, it's the way the backend works. One space is kept of each set.
205 title = new mw.Title( 'Foo __ \t __ bar' );
206 assert.equal( title.getMain(), 'Foo_bar', 'Merge multiple types of whitespace/underscores into a single underscore' );
207
208 // Regression test: Previously it would only detect an extension if there is no space after it
209 title = new mw.Title( 'Example.js ' );
210 assert.equal( title.getExtension(), 'js', 'Space after an extension is stripped' );
211
212 title = new mw.Title( 'Example#foo' );
213 assert.equal( title.getFragment(), 'foo', 'Fragment' );
214
215 title = new mw.Title( 'Example#_foo_bar baz_' );
216 assert.equal( title.getFragment(), ' foo bar baz', 'Fragment' );
217 } );
218
219 QUnit.test( 'Namespace detection and conversion', 10, function ( assert ) {
220 var title;
221
222 title = new mw.Title( 'File:User:Example' );
223 assert.equal( title.getNamespaceId(), 6, 'Titles can contain namespace prefixes, which are otherwise ignored' );
224
225 title = new mw.Title( 'Example', 6 );
226 assert.equal( title.getNamespaceId(), 6, 'Default namespace passed is used' );
227
228 title = new mw.Title( 'User:Example', 6 );
229 assert.equal( title.getNamespaceId(), 2, 'Included namespace prefix overrides the given default' );
230
231 title = new mw.Title( ':Example', 6 );
232 assert.equal( title.getNamespaceId(), 0, 'Colon forces main namespace' );
233
234 title = new mw.Title( 'something.PDF', 6 );
235 assert.equal( title.toString(), 'File:Something.PDF' );
236
237 title = new mw.Title( 'NeilK', 3 );
238 assert.equal( title.toString(), 'User_talk:NeilK' );
239 assert.equal( title.toText(), 'User talk:NeilK' );
240
241 title = new mw.Title( 'Frobisher', 100 );
242 assert.equal( title.toString(), 'Penguins:Frobisher' );
243
244 title = new mw.Title( 'antarctic_waterfowl:flightless_yet_cute.jpg' );
245 assert.equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
246
247 title = new mw.Title( 'Penguins:flightless_yet_cute.jpg' );
248 assert.equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
249 } );
250
251 QUnit.test( 'Throw error on invalid title', 1, function ( assert ) {
252 assert.throws( function () {
253 return new mw.Title( '' );
254 }, 'Throw error on empty string' );
255 } );
256
257 QUnit.test( 'Case-sensivity', 3, function ( assert ) {
258 var title;
259
260 // Default config
261 mw.config.set( 'wgCaseSensitiveNamespaces', [] );
262
263 title = new mw.Title( 'article' );
264 assert.equal( title.toString(), 'Article', 'Default config: No sensitive namespaces by default. First-letter becomes uppercase' );
265
266 // $wgCapitalLinks = false;
267 mw.config.set( 'wgCaseSensitiveNamespaces', [0, -2, 1, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15] );
268
269 title = new mw.Title( 'article' );
270 assert.equal( title.toString(), 'article', '$wgCapitalLinks=false: Article namespace is sensitive, first-letter case stays lowercase' );
271
272 title = new mw.Title( 'john', 2 );
273 assert.equal( title.toString(), 'User:John', '$wgCapitalLinks=false: User namespace is insensitive, first-letter becomes uppercase' );
274 } );
275
276 QUnit.test( 'toString / toText', 2, function ( assert ) {
277 var title = new mw.Title( 'Some random page' );
278
279 assert.equal( title.toString(), title.getPrefixedDb() );
280 assert.equal( title.toText(), title.getPrefixedText() );
281 } );
282
283 QUnit.test( 'getExtension', 7, function ( assert ) {
284 function extTest( pagename, ext, description ) {
285 var title = new mw.Title( pagename );
286 assert.equal( title.getExtension(), ext, description || pagename );
287 }
288
289 extTest( 'MediaWiki:Vector.js', 'js' );
290 extTest( 'User:Example/common.css', 'css' );
291 extTest( 'File:Example.longextension', 'longextension', 'Extension parsing not limited (bug 36151)' );
292 extTest( 'Example/information.json', 'json', 'Extension parsing not restricted from any namespace' );
293 extTest( 'Foo.', null, 'Trailing dot is not an extension' );
294 extTest( 'Foo..', null, 'Trailing dots are not an extension' );
295 extTest( 'Foo.a.', null, 'Page name with dots and ending in a dot does not have an extension' );
296
297 // @broken: Throws an exception
298 // extTest( '.NET', null, 'Leading dot is (or is not?) an extension' );
299 } );
300
301 QUnit.test( 'exists', 3, function ( assert ) {
302 var title;
303
304 // Empty registry, checks default to null
305
306 title = new mw.Title( 'Some random page', 4 );
307 assert.strictEqual( title.exists(), null, 'Return null with empty existance registry' );
308
309 // Basic registry, checks default to boolean
310 mw.Title.exist.set( ['Does_exist', 'User_talk:NeilK', 'Wikipedia:Sandbox_rules'], true );
311 mw.Title.exist.set( ['Does_not_exist', 'User:John', 'Foobar'], false );
312
313 title = new mw.Title( 'Project:Sandbox rules' );
314 assert.assertTrue( title.exists(), 'Return true for page titles marked as existing' );
315 title = new mw.Title( 'Foobar' );
316 assert.assertFalse( title.exists(), 'Return false for page titles marked as nonexistent' );
317
318 } );
319
320 QUnit.test( 'getUrl', 3, function ( assert ) {
321 var title;
322
323 // Config
324 mw.config.set( 'wgArticlePath', '/wiki/$1' );
325
326 title = new mw.Title( 'Foobar' );
327 assert.equal( title.getUrl(), '/wiki/Foobar', 'Basic functionality, getUrl uses mw.util.getUrl' );
328 assert.equal( title.getUrl({ action: 'edit' }), '/wiki/Foobar?action=edit', 'Basic functionality, \'params\' parameter' );
329
330 title = new mw.Title( 'John Doe', 3 );
331 assert.equal( title.getUrl(), '/wiki/User_talk:John_Doe', 'Escaping in title and namespace for urls' );
332 } );
333
334 QUnit.test( 'newFromImg', 40, function ( assert ) {
335 var title, i, thisCase, prefix,
336 cases = [
337 {
338 url: '//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Princess_Alexandra_of_Denmark_%28later_Queen_Alexandra%2C_wife_of_Edward_VII%29_with_her_two_eldest_sons%2C_Prince_Albert_Victor_%28Eddy%29_and_George_Frederick_Ernest_Albert_%28later_George_V%29.jpg/939px-thumbnail.jpg',
339 typeOfUrl: 'Hashed thumb with shortened path',
340 nameText: 'Princess Alexandra of Denmark (later Queen Alexandra, wife of Edward VII) with her two eldest sons, Prince Albert Victor (Eddy) and George Frederick Ernest Albert (later George V)',
341 prefixedText: 'File:Princess Alexandra of Denmark (later Queen Alexandra, wife of Edward VII) with her two eldest sons, Prince Albert Victor (Eddy) and George Frederick Ernest Albert (later George V).jpg'
342 },
343 {
344 url: '/wiki/images/thumb/9/91/Anticlockwise_heliotrope%27s.jpg/99px-Anticlockwise_heliotrope%27s.jpg',
345 typeOfUrl: 'Normal hashed directory thumbnail',
346 nameText: 'Anticlockwise heliotrope\'s',
347 prefixedText: 'File:Anticlockwise heliotrope\'s.jpg'
348 },
349
350 {
351 url: '/wiki/images/thumb/8/80/Wikipedia-logo-v2.svg/langde-150px-Wikipedia-logo-v2.svg.png',
352 typeOfUrl: 'Normal hashed directory thumbnail with complex thumbnail parameters',
353 nameText: 'Wikipedia-logo-v2',
354 prefixedText: 'File:Wikipedia-logo-v2.svg'
355 },
356
357 {
358 url: '//upload.wikimedia.org/wikipedia/commons/thumb/8/80/Wikipedia-logo-v2.svg/150px-Wikipedia-logo-v2.svg.png',
359 typeOfUrl: 'Commons thumbnail',
360 nameText: 'Wikipedia-logo-v2',
361 prefixedText: 'File:Wikipedia-logo-v2.svg'
362 },
363
364 {
365 url: '/wiki/images/9/91/Anticlockwise_heliotrope%27s.jpg',
366 typeOfUrl: 'Full image',
367 nameText: 'Anticlockwise heliotrope\'s',
368 prefixedText: 'File:Anticlockwise heliotrope\'s.jpg'
369 },
370
371 {
372 url: 'http://localhost/thumb.php?f=Stuffless_Figaro%27s.jpg&width=180',
373 typeOfUrl: 'thumb.php-based thumbnail',
374 nameText: 'Stuffless Figaro\'s',
375 prefixedText: 'File:Stuffless Figaro\'s.jpg'
376 },
377
378 {
379 url: '/wikipedia/commons/thumb/Wikipedia-logo-v2.svg/150px-Wikipedia-logo-v2.svg.png',
380 typeOfUrl: 'Commons unhashed thumbnail',
381 nameText: 'Wikipedia-logo-v2',
382 prefixedText: 'File:Wikipedia-logo-v2.svg'
383 },
384
385 {
386 url: '/wikipedia/commons/thumb/Wikipedia-logo-v2.svg/langde-150px-Wikipedia-logo-v2.svg.png',
387 typeOfUrl: 'Commons unhashed thumbnail with complex thumbnail parameters',
388 nameText: 'Wikipedia-logo-v2',
389 prefixedText: 'File:Wikipedia-logo-v2.svg'
390 },
391
392 {
393 url: '/wiki/images/Anticlockwise_heliotrope%27s.jpg',
394 typeOfUrl: 'Unhashed local file',
395 nameText: 'Anticlockwise heliotrope\'s',
396 prefixedText: 'File:Anticlockwise heliotrope\'s.jpg'
397 },
398
399 {
400 url: '',
401 typeOfUrl: 'Empty string'
402 },
403
404 {
405 url: 'foo',
406 typeOfUrl: 'String with only alphabet characters'
407 },
408
409 {
410 url: 'foobar.foobar',
411 typeOfUrl: 'Not a file path'
412 },
413
414 {
415 url: '/a/a0/blah blah blah',
416 typeOfUrl: 'Space characters'
417 }
418 ];
419
420 for ( i = 0; i < cases.length; i++ ) {
421 thisCase = cases[i];
422 title = mw.Title.newFromImg( { src: thisCase.url } );
423
424 if ( thisCase.nameText !== undefined ) {
425 prefix = '[' + thisCase.typeOfUrl + ' URL' + '] ';
426
427 assert.notStrictEqual( title, null, prefix + 'Parses successfully' );
428 assert.equal( title.getNameText(), thisCase.nameText, prefix + 'Filename matches original' );
429 assert.equal( title.getPrefixedText(), thisCase.prefixedText, prefix + 'File page title matches original' );
430 assert.equal( title.getNamespaceId(), 6, prefix + 'Namespace ID matches File namespace' );
431 } else {
432 assert.strictEqual( title, null, thisCase.typeOfUrl + ', should not produce an mw.Title object' );
433 }
434 }
435 } );
436
437 }( mediaWiki, jQuery ) );