MediaWiki  1.27.2
LanguageTest.php
Go to the documentation of this file.
1 <?php
2 
9  $this->assertEquals(
10  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
11  $this->getLang()->normalizeForSearch(
12  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
13  ),
14  'convertDoubleWidth() with the full alphabet and digits'
15  );
16  }
17 
22  public function testFormatTimePeriod( $seconds, $format, $expected, $desc ) {
23  $this->assertEquals( $expected, $this->getLang()->formatTimePeriod( $seconds, $format ), $desc );
24  }
25 
26  public static function provideFormattableTimes() {
27  return [
28  [
29  9.45,
30  [],
31  '9.5 s',
32  'formatTimePeriod() rounding (<10s)'
33  ],
34  [
35  9.45,
36  [ 'noabbrevs' => true ],
37  '9.5 seconds',
38  'formatTimePeriod() rounding (<10s)'
39  ],
40  [
41  9.95,
42  [],
43  '10 s',
44  'formatTimePeriod() rounding (<10s)'
45  ],
46  [
47  9.95,
48  [ 'noabbrevs' => true ],
49  '10 seconds',
50  'formatTimePeriod() rounding (<10s)'
51  ],
52  [
53  59.55,
54  [],
55  '1 min 0 s',
56  'formatTimePeriod() rounding (<60s)'
57  ],
58  [
59  59.55,
60  [ 'noabbrevs' => true ],
61  '1 minute 0 seconds',
62  'formatTimePeriod() rounding (<60s)'
63  ],
64  [
65  119.55,
66  [],
67  '2 min 0 s',
68  'formatTimePeriod() rounding (<1h)'
69  ],
70  [
71  119.55,
72  [ 'noabbrevs' => true ],
73  '2 minutes 0 seconds',
74  'formatTimePeriod() rounding (<1h)'
75  ],
76  [
77  3599.55,
78  [],
79  '1 h 0 min 0 s',
80  'formatTimePeriod() rounding (<1h)'
81  ],
82  [
83  3599.55,
84  [ 'noabbrevs' => true ],
85  '1 hour 0 minutes 0 seconds',
86  'formatTimePeriod() rounding (<1h)'
87  ],
88  [
89  7199.55,
90  [],
91  '2 h 0 min 0 s',
92  'formatTimePeriod() rounding (>=1h)'
93  ],
94  [
95  7199.55,
96  [ 'noabbrevs' => true ],
97  '2 hours 0 minutes 0 seconds',
98  'formatTimePeriod() rounding (>=1h)'
99  ],
100  [
101  7199.55,
102  'avoidseconds',
103  '2 h 0 min',
104  'formatTimePeriod() rounding (>=1h), avoidseconds'
105  ],
106  [
107  7199.55,
108  [ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
109  '2 hours 0 minutes',
110  'formatTimePeriod() rounding (>=1h), avoidseconds'
111  ],
112  [
113  7199.55,
114  'avoidminutes',
115  '2 h 0 min',
116  'formatTimePeriod() rounding (>=1h), avoidminutes'
117  ],
118  [
119  7199.55,
120  [ 'avoid' => 'avoidminutes', 'noabbrevs' => true ],
121  '2 hours 0 minutes',
122  'formatTimePeriod() rounding (>=1h), avoidminutes'
123  ],
124  [
125  172799.55,
126  'avoidseconds',
127  '48 h 0 min',
128  'formatTimePeriod() rounding (=48h), avoidseconds'
129  ],
130  [
131  172799.55,
132  [ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
133  '48 hours 0 minutes',
134  'formatTimePeriod() rounding (=48h), avoidseconds'
135  ],
136  [
137  259199.55,
138  'avoidminutes',
139  '3 d 0 h',
140  'formatTimePeriod() rounding (>48h), avoidminutes'
141  ],
142  [
143  259199.55,
144  [ 'avoid' => 'avoidminutes', 'noabbrevs' => true ],
145  '3 days 0 hours',
146  'formatTimePeriod() rounding (>48h), avoidminutes'
147  ],
148  [
149  176399.55,
150  'avoidseconds',
151  '2 d 1 h 0 min',
152  'formatTimePeriod() rounding (>48h), avoidseconds'
153  ],
154  [
155  176399.55,
156  [ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
157  '2 days 1 hour 0 minutes',
158  'formatTimePeriod() rounding (>48h), avoidseconds'
159  ],
160  [
161  176399.55,
162  'avoidminutes',
163  '2 d 1 h',
164  'formatTimePeriod() rounding (>48h), avoidminutes'
165  ],
166  [
167  176399.55,
168  [ 'avoid' => 'avoidminutes', 'noabbrevs' => true ],
169  '2 days 1 hour',
170  'formatTimePeriod() rounding (>48h), avoidminutes'
171  ],
172  [
173  259199.55,
174  'avoidseconds',
175  '3 d 0 h 0 min',
176  'formatTimePeriod() rounding (>48h), avoidseconds'
177  ],
178  [
179  259199.55,
180  [ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
181  '3 days 0 hours 0 minutes',
182  'formatTimePeriod() rounding (>48h), avoidseconds'
183  ],
184  [
185  172801.55,
186  'avoidseconds',
187  '2 d 0 h 0 min',
188  'formatTimePeriod() rounding, (>48h), avoidseconds'
189  ],
190  [
191  172801.55,
192  [ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
193  '2 days 0 hours 0 minutes',
194  'formatTimePeriod() rounding, (>48h), avoidseconds'
195  ],
196  [
197  176460.55,
198  [],
199  '2 d 1 h 1 min 1 s',
200  'formatTimePeriod() rounding, recursion, (>48h)'
201  ],
202  [
203  176460.55,
204  [ 'noabbrevs' => true ],
205  '2 days 1 hour 1 minute 1 second',
206  'formatTimePeriod() rounding, recursion, (>48h)'
207  ],
208  ];
209  }
210 
214  public function testTruncate() {
215  $this->assertEquals(
216  "XXX",
217  $this->getLang()->truncate( "1234567890", 0, 'XXX' ),
218  'truncate prefix, len 0, small ellipsis'
219  );
220 
221  $this->assertEquals(
222  "12345XXX",
223  $this->getLang()->truncate( "1234567890", 8, 'XXX' ),
224  'truncate prefix, small ellipsis'
225  );
226 
227  $this->assertEquals(
228  "123456789",
229  $this->getLang()->truncate( "123456789", 5, 'XXXXXXXXXXXXXXX' ),
230  'truncate prefix, large ellipsis'
231  );
232 
233  $this->assertEquals(
234  "XXX67890",
235  $this->getLang()->truncate( "1234567890", -8, 'XXX' ),
236  'truncate suffix, small ellipsis'
237  );
238 
239  $this->assertEquals(
240  "123456789",
241  $this->getLang()->truncate( "123456789", -5, 'XXXXXXXXXXXXXXX' ),
242  'truncate suffix, large ellipsis'
243  );
244  $this->assertEquals(
245  "123XXX",
246  $this->getLang()->truncate( "123 ", 9, 'XXX' ),
247  'truncate prefix, with spaces'
248  );
249  $this->assertEquals(
250  "12345XXX",
251  $this->getLang()->truncate( "12345 8", 11, 'XXX' ),
252  'truncate prefix, with spaces and non-space ending'
253  );
254  $this->assertEquals(
255  "XXX234",
256  $this->getLang()->truncate( "1 234", -8, 'XXX' ),
257  'truncate suffix, with spaces'
258  );
259  $this->assertEquals(
260  "12345XXX",
261  $this->getLang()->truncate( "1234567890", 5, 'XXX', false ),
262  'truncate without adjustment'
263  );
264  $this->assertEquals(
265  "泰乐菌...",
266  $this->getLang()->truncate( "泰乐菌素123456789", 11, '...', false ),
267  'truncate does not chop Unicode characters in half'
268  );
269  $this->assertEquals(
270  "\n泰乐菌...",
271  $this->getLang()->truncate( "\n泰乐菌素123456789", 12, '...', false ),
272  'truncate does not chop Unicode characters in half if there is a preceding newline'
273  );
274  }
275 
280  public function testTruncateHtml( $len, $ellipsis, $input, $expected ) {
281  // Actual HTML...
282  $this->assertEquals(
283  $expected,
284  $this->getLang()->truncateHtml( $input, $len, $ellipsis )
285  );
286  }
287 
291  public static function provideHTMLTruncateData() {
292  return [
293  [ 0, 'XXX', "1234567890", "XXX" ],
294  [ 8, 'XXX', "1234567890", "12345XXX" ],
295  [ 5, 'XXXXXXXXXXXXXXX', '1234567890', "1234567890" ],
296  [ 2, '***',
297  '<p><span style="font-weight:bold;"></span></p>',
298  '<p><span style="font-weight:bold;"></span></p>',
299  ],
300  [ 2, '***',
301  '<p><span style="font-weight:bold;">123456789</span></p>',
302  '<p><span style="font-weight:bold;">***</span></p>',
303  ],
304  [ 2, '***',
305  '<p><span style="font-weight:bold;">&nbsp;23456789</span></p>',
306  '<p><span style="font-weight:bold;">***</span></p>',
307  ],
308  [ 3, '***',
309  '<p><span style="font-weight:bold;">123456789</span></p>',
310  '<p><span style="font-weight:bold;">***</span></p>',
311  ],
312  [ 4, '***',
313  '<p><span style="font-weight:bold;">123456789</span></p>',
314  '<p><span style="font-weight:bold;">1***</span></p>',
315  ],
316  [ 5, '***',
317  '<tt><span style="font-weight:bold;">123456789</span></tt>',
318  '<tt><span style="font-weight:bold;">12***</span></tt>',
319  ],
320  [ 6, '***',
321  '<p><a href="www.mediawiki.org">123456789</a></p>',
322  '<p><a href="www.mediawiki.org">123***</a></p>',
323  ],
324  [ 6, '***',
325  '<p><a href="www.mediawiki.org">12&nbsp;456789</a></p>',
326  '<p><a href="www.mediawiki.org">12&nbsp;***</a></p>',
327  ],
328  [ 7, '***',
329  '<small><span style="font-weight:bold;">123<p id="#moo">456</p>789</span></small>',
330  '<small><span style="font-weight:bold;">123<p id="#moo">4***</p></span></small>',
331  ],
332  [ 8, '***',
333  '<div><span style="font-weight:bold;">123<span>4</span>56789</span></div>',
334  '<div><span style="font-weight:bold;">123<span>4</span>5***</span></div>',
335  ],
336  [ 9, '***',
337  '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
338  '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
339  ],
340  [ 10, '***',
341  '<p><font style="font-weight:bold;">123456789</font></p>',
342  '<p><font style="font-weight:bold;">123456789</font></p>',
343  ],
344  ];
345  }
346 
352  public function testWellFormedLanguageTag( $code, $message = '' ) {
353  $this->assertTrue(
355  "validating code $code $message"
356  );
357  }
358 
365  public static function provideWellFormedLanguageTags() {
366  return [
367  [ 'fr', 'two-letter code' ],
368  [ 'fr-latn', 'two-letter code with lower case script code' ],
369  [ 'fr-Latn-FR', 'two-letter code with title case script code and uppercase country code' ],
370  [ 'fr-Latn-419', 'two-letter code with title case script code and region number' ],
371  [ 'fr-FR', 'two-letter code with uppercase' ],
372  [ 'ax-TZ', 'Not in the registry, but well-formed' ],
373  [ 'fr-shadok', 'two-letter code with variant' ],
374  [ 'fr-y-myext-myext2', 'non-x singleton' ],
375  [ 'fra-Latn', 'ISO 639 can be 3-letters' ],
376  [ 'fra', 'three-letter language code' ],
377  [ 'fra-FX', 'three-letter language code with country code' ],
378  [ 'i-klingon', 'grandfathered with singleton' ],
379  [ 'I-kLINgon', 'tags are case-insensitive...' ],
380  [ 'no-bok', 'grandfathered without singleton' ],
381  [ 'i-enochian', 'Grandfathered' ],
382  [ 'x-fr-CH', 'private use' ],
383  [ 'es-419', 'two-letter code with region number' ],
384  [ 'en-Latn-GB-boont-r-extended-sequence-x-private', 'weird, but well-formed' ],
385  [ 'ab-x-abc-x-abc', 'anything goes after x' ],
386  [ 'ab-x-abc-a-a', 'anything goes after x, including several non-x singletons' ],
387  [ 'i-default', 'grandfathered' ],
388  [ 'abcd-Latn', 'Language of 4 chars reserved for future use' ],
389  [ 'AaBbCcDd-x-y-any-x', 'Language of 5-8 chars, registered' ],
390  [ 'de-CH-1901', 'with country and year' ],
391  [ 'en-US-x-twain', 'with country and singleton' ],
392  [ 'zh-cmn', 'three-letter variant' ],
393  [ 'zh-cmn-Hant', 'three-letter variant and script' ],
394  [ 'zh-cmn-Hant-HK', 'three-letter variant, script and country' ],
395  [ 'xr-p-lze', 'Extension' ],
396  ];
397  }
398 
404  public function testMalformedLanguageTag( $code, $message = '' ) {
405  $this->assertFalse(
407  "validating that code $code is a malformed language tag - $message"
408  );
409  }
410 
417  public static function provideMalformedLanguageTags() {
418  return [
419  [ 'f', 'language too short' ],
420  [ 'f-Latn', 'language too short with script' ],
421  [ 'xr-lxs-qut', 'variants too short' ], # extlangS
422  [ 'fr-Latn-F', 'region too short' ],
423  [ 'a-value', 'language too short with region' ],
424  [ 'tlh-a-b-foo', 'valid three-letter with wrong variant' ],
425  [
426  'i-notexist',
427  'grandfathered but not registered: invalid, even if we only test well-formedness'
428  ],
429  [ 'abcdefghi-012345678', 'numbers too long' ],
430  [ 'ab-abc-abc-abc-abc', 'invalid extensions' ],
431  [ 'ab-abcd-abc', 'invalid extensions' ],
432  [ 'ab-ab-abc', 'invalid extensions' ],
433  [ 'ab-123-abc', 'invalid extensions' ],
434  [ 'a-Hant-ZH', 'short language with valid extensions' ],
435  [ 'a1-Hant-ZH', 'invalid character in language' ],
436  [ 'ab-abcde-abc', 'invalid extensions' ],
437  [ 'ab-1abc-abc', 'invalid characters in extensions' ],
438  [ 'ab-ab-abcd', 'invalid order of extensions' ],
439  [ 'ab-123-abcd', 'invalid order of extensions' ],
440  [ 'ab-abcde-abcd', 'invalid extensions' ],
441  [ 'ab-1abc-abcd', 'invalid characters in extensions' ],
442  [ 'ab-a-b', 'extensions too short' ],
443  [ 'ab-a-x', 'extensions too short, even with singleton' ],
444  [ 'ab--ab', 'two separators' ],
445  [ 'ab-abc-', 'separator in the end' ],
446  [ '-ab-abc', 'separator in the beginning' ],
447  [ 'abcd-efg', 'language too long' ],
448  [ 'aabbccddE', 'tag too long' ],
449  [ 'pa_guru', 'A tag with underscore is invalid in strict mode' ],
450  [ 'de-f', 'subtag too short' ],
451  ];
452  }
453 
458  public function testLenientLanguageTag() {
459  $this->assertTrue(
460  Language::isWellFormedLanguageTag( 'pa_guru', true ),
461  'pa_guru is a well-formed language tag in lenient mode'
462  );
463  }
464 
470  public function testBuiltInCodeValidation( $code, $expected, $message = '' ) {
471  $this->assertEquals( $expected,
473  "validating code $code $message"
474  );
475  }
476 
477  public static function provideLanguageCodes() {
478  return [
479  [ 'fr', true, 'Two letters, minor case' ],
480  [ 'EN', false, 'Two letters, upper case' ],
481  [ 'tyv', true, 'Three letters' ],
482  [ 'tokipona', true, 'long language code' ],
483  [ 'be-tarask', true, 'With dash' ],
484  [ 'be-x-old', true, 'With extension (two dashes)' ],
485  [ 'be_tarask', false, 'Reject underscores' ],
486  ];
487  }
488 
494  public function testKnownLanguageTag( $code, $message = '' ) {
495  $this->assertTrue(
497  "validating code $code - $message"
498  );
499  }
500 
501  public static function provideKnownLanguageTags() {
502  return [
503  [ 'fr', 'simple code' ],
504  [ 'bat-smg', 'an MW legacy tag' ],
505  [ 'sgs', 'an internal standard MW name, for which a legacy tag is used externally' ],
506  ];
507  }
508 
512  public function testKnownCldrLanguageTag() {
513  if ( !class_exists( 'LanguageNames' ) ) {
514  $this->markTestSkipped( 'The LanguageNames class is not available. '
515  . 'The CLDR extension is probably not installed.' );
516  }
517 
518  $this->assertTrue(
519  (bool)Language::isKnownLanguageTag( 'pal' ),
520  'validating code "pal" an ancient language, which probably will '
521  . 'not appear in Names.php, but appears in CLDR in English'
522  );
523  }
524 
530  public function testUnknownLanguageTag( $code, $message = '' ) {
531  $this->assertFalse(
533  "checking that code $code is invalid - $message"
534  );
535  }
536 
537  public static function provideUnknownLanguageTags() {
538  return [
539  [ 'mw', 'non-existent two-letter code' ],
540  [ 'foo"<bar', 'very invalid language code' ],
541  ];
542  }
543 
550  $this->getLang()->sprintfDate( 'xiY', '1234567890123' );
551  }
552 
559  $this->getLang()->sprintfDate( 'xiY', '123456789012345' );
560  }
561 
568  $this->getLang()->sprintfDate( 'xiY', '-1234567890123' );
569  }
570 
575  public function testSprintfDate( $format, $ts, $expected, $msg ) {
576  $ttl = null;
577  $this->assertEquals(
578  $expected,
579  $this->getLang()->sprintfDate( $format, $ts, null, $ttl ),
580  "sprintfDate('$format', '$ts'): $msg"
581  );
582  if ( $ttl ) {
583  $dt = new DateTime( $ts );
584  $lastValidTS = $dt->add( new DateInterval( 'PT' . ( $ttl - 1 ) . 'S' ) )->format( 'YmdHis' );
585  $this->assertEquals(
586  $expected,
587  $this->getLang()->sprintfDate( $format, $lastValidTS, null ),
588  "sprintfDate('$format', '$ts'): TTL $ttl too high (output was different at $lastValidTS)"
589  );
590  } else {
591  // advance the time enough to make all of the possible outputs different (except possibly L)
592  $dt = new DateTime( $ts );
593  $newTS = $dt->add( new DateInterval( 'P1Y1M8DT13H1M1S' ) )->format( 'YmdHis' );
594  $this->assertEquals(
595  $expected,
596  $this->getLang()->sprintfDate( $format, $newTS, null ),
597  "sprintfDate('$format', '$ts'): Missing TTL (output was different at $newTS)"
598  );
599  }
600  }
601 
607  public function testSprintfDateNoZone( $format, $ts, $expected, $ignore, $msg ) {
608  $oldTZ = date_default_timezone_get();
609  $res = date_default_timezone_set( 'Asia/Seoul' );
610  if ( !$res ) {
611  $this->markTestSkipped( "Error setting Timezone" );
612  }
613 
614  $this->assertEquals(
615  $expected,
616  $this->getLang()->sprintfDate( $format, $ts ),
617  "sprintfDate('$format', '$ts'): $msg"
618  );
619 
620  date_default_timezone_set( $oldTZ );
621  }
622 
628  public function testSprintfDateTZ( $format, $ts, $ignore, $expected, $msg ) {
629  $tz = new DateTimeZone( 'Asia/Seoul' );
630  if ( !$tz ) {
631  $this->markTestSkipped( "Error getting Timezone" );
632  }
633 
634  $this->assertEquals(
635  $expected,
636  $this->getLang()->sprintfDate( $format, $ts, $tz ),
637  "sprintfDate('$format', '$ts', 'Asia/Seoul'): $msg"
638  );
639  }
640 
641  public static function provideSprintfDateSamples() {
642  return [
643  [
644  'xiY',
645  '20111212000000',
646  '1390', // note because we're testing English locale we get Latin-standard digits
647  '1390',
648  'Iranian calendar full year'
649  ],
650  [
651  'xiy',
652  '20111212000000',
653  '90',
654  '90',
655  'Iranian calendar short year'
656  ],
657  [
658  'o',
659  '20120101235000',
660  '2011',
661  '2011',
662  'ISO 8601 (week) year'
663  ],
664  [
665  'W',
666  '20120101235000',
667  '52',
668  '52',
669  'Week number'
670  ],
671  [
672  'W',
673  '20120102235000',
674  '1',
675  '1',
676  'Week number'
677  ],
678  [
679  'o-\\WW-N',
680  '20091231235000',
681  '2009-W53-4',
682  '2009-W53-4',
683  'leap week'
684  ],
685  // What follows is mostly copied from
686  // https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
687  [
688  'Y',
689  '20120102090705',
690  '2012',
691  '2012',
692  'Full year'
693  ],
694  [
695  'y',
696  '20120102090705',
697  '12',
698  '12',
699  '2 digit year'
700  ],
701  [
702  'L',
703  '20120102090705',
704  '1',
705  '1',
706  'Leap year'
707  ],
708  [
709  'n',
710  '20120102090705',
711  '1',
712  '1',
713  'Month index, not zero pad'
714  ],
715  [
716  'N',
717  '20120102090705',
718  '01',
719  '01',
720  'Month index. Zero pad'
721  ],
722  [
723  'M',
724  '20120102090705',
725  'Jan',
726  'Jan',
727  'Month abbrev'
728  ],
729  [
730  'F',
731  '20120102090705',
732  'January',
733  'January',
734  'Full month'
735  ],
736  [
737  'xg',
738  '20120102090705',
739  'January',
740  'January',
741  'Genitive month name (same in EN)'
742  ],
743  [
744  'j',
745  '20120102090705',
746  '2',
747  '2',
748  'Day of month (not zero pad)'
749  ],
750  [
751  'd',
752  '20120102090705',
753  '02',
754  '02',
755  'Day of month (zero-pad)'
756  ],
757  [
758  'z',
759  '20120102090705',
760  '1',
761  '1',
762  'Day of year (zero-indexed)'
763  ],
764  [
765  'D',
766  '20120102090705',
767  'Mon',
768  'Mon',
769  'Day of week (abbrev)'
770  ],
771  [
772  'l',
773  '20120102090705',
774  'Monday',
775  'Monday',
776  'Full day of week'
777  ],
778  [
779  'N',
780  '20120101090705',
781  '7',
782  '7',
783  'Day of week (Mon=1, Sun=7)'
784  ],
785  [
786  'w',
787  '20120101090705',
788  '0',
789  '0',
790  'Day of week (Sun=0, Sat=6)'
791  ],
792  [
793  'N',
794  '20120102090705',
795  '1',
796  '1',
797  'Day of week'
798  ],
799  [
800  'a',
801  '20120102090705',
802  'am',
803  'am',
804  'am vs pm'
805  ],
806  [
807  'A',
808  '20120102120000',
809  'PM',
810  'PM',
811  'AM vs PM'
812  ],
813  [
814  'a',
815  '20120102000000',
816  'am',
817  'am',
818  'AM vs PM'
819  ],
820  [
821  'g',
822  '20120102090705',
823  '9',
824  '9',
825  '12 hour, not Zero'
826  ],
827  [
828  'h',
829  '20120102090705',
830  '09',
831  '09',
832  '12 hour, zero padded'
833  ],
834  [
835  'G',
836  '20120102090705',
837  '9',
838  '9',
839  '24 hour, not zero'
840  ],
841  [
842  'H',
843  '20120102090705',
844  '09',
845  '09',
846  '24 hour, zero'
847  ],
848  [
849  'H',
850  '20120102110705',
851  '11',
852  '11',
853  '24 hour, zero'
854  ],
855  [
856  'i',
857  '20120102090705',
858  '07',
859  '07',
860  'Minutes'
861  ],
862  [
863  's',
864  '20120102090705',
865  '05',
866  '05',
867  'seconds'
868  ],
869  [
870  'U',
871  '20120102090705',
872  '1325495225',
873  '1325462825',
874  'unix time'
875  ],
876  [
877  't',
878  '20120102090705',
879  '31',
880  '31',
881  'Days in current month'
882  ],
883  [
884  'c',
885  '20120102090705',
886  '2012-01-02T09:07:05+00:00',
887  '2012-01-02T09:07:05+09:00',
888  'ISO 8601 timestamp'
889  ],
890  [
891  'r',
892  '20120102090705',
893  'Mon, 02 Jan 2012 09:07:05 +0000',
894  'Mon, 02 Jan 2012 09:07:05 +0900',
895  'RFC 5322'
896  ],
897  [
898  'e',
899  '20120102090705',
900  'UTC',
901  'Asia/Seoul',
902  'Timezone identifier'
903  ],
904  [
905  'I',
906  '19880602090705',
907  '0',
908  '1',
909  'DST indicator'
910  ],
911  [
912  'O',
913  '20120102090705',
914  '+0000',
915  '+0900',
916  'Timezone offset'
917  ],
918  [
919  'P',
920  '20120102090705',
921  '+00:00',
922  '+09:00',
923  'Timezone offset with colon'
924  ],
925  [
926  'T',
927  '20120102090705',
928  'UTC',
929  'KST',
930  'Timezone abbreviation'
931  ],
932  [
933  'Z',
934  '20120102090705',
935  '0',
936  '32400',
937  'Timezone offset in seconds'
938  ],
939  [
940  'xmj xmF xmn xmY',
941  '20120102090705',
942  '7 Safar 2 1433',
943  '7 Safar 2 1433',
944  'Islamic'
945  ],
946  [
947  'xij xiF xin xiY',
948  '20120102090705',
949  '12 Dey 10 1390',
950  '12 Dey 10 1390',
951  'Iranian'
952  ],
953  [
954  'xjj xjF xjn xjY',
955  '20120102090705',
956  '7 Tevet 4 5772',
957  '7 Tevet 4 5772',
958  'Hebrew'
959  ],
960  [
961  'xjt',
962  '20120102090705',
963  '29',
964  '29',
965  'Hebrew number of days in month'
966  ],
967  [
968  'xjx',
969  '20120102090705',
970  'Tevet',
971  'Tevet',
972  'Hebrew genitive month name (No difference in EN)'
973  ],
974  [
975  'xkY',
976  '20120102090705',
977  '2555',
978  '2555',
979  'Thai year'
980  ],
981  [
982  'xoY',
983  '20120102090705',
984  '101',
985  '101',
986  'Minguo'
987  ],
988  [
989  'xtY',
990  '20120102090705',
991  '平成24',
992  '平成24',
993  'nengo'
994  ],
995  [
996  'xrxkYY',
997  '20120102090705',
998  'MMDLV2012',
999  'MMDLV2012',
1000  'Roman numerals'
1001  ],
1002  [
1003  'xhxjYY',
1004  '20120102090705',
1005  'ה\'תשע"ב2012',
1006  'ה\'תשע"ב2012',
1007  'Hebrew numberals'
1008  ],
1009  [
1010  'xnY',
1011  '20120102090705',
1012  '2012',
1013  '2012',
1014  'Raw numerals (doesn\'t mean much in EN)'
1015  ],
1016  [
1017  '[[Y "(yea"\\r)]] \\"xx\\"',
1018  '20120102090705',
1019  '[[2012 (year)]] "x"',
1020  '[[2012 (year)]] "x"',
1021  'Various escaping'
1022  ],
1023 
1024  ];
1025  }
1026 
1031  public function testFormatSize( $size, $expected, $msg ) {
1032  $this->assertEquals(
1033  $expected,
1034  $this->getLang()->formatSize( $size ),
1035  "formatSize('$size'): $msg"
1036  );
1037  }
1038 
1039  public static function provideFormatSizes() {
1040  return [
1041  [
1042  0,
1043  "0 bytes",
1044  "Zero bytes"
1045  ],
1046  [
1047  1024,
1048  "1 KB",
1049  "1 kilobyte"
1050  ],
1051  [
1052  1024 * 1024,
1053  "1 MB",
1054  "1,024 megabytes"
1055  ],
1056  [
1057  1024 * 1024 * 1024,
1058  "1 GB",
1059  "1 gigabyte"
1060  ],
1061  [
1062  pow( 1024, 4 ),
1063  "1 TB",
1064  "1 terabyte"
1065  ],
1066  [
1067  pow( 1024, 5 ),
1068  "1 PB",
1069  "1 petabyte"
1070  ],
1071  [
1072  pow( 1024, 6 ),
1073  "1 EB",
1074  "1,024 exabyte"
1075  ],
1076  [
1077  pow( 1024, 7 ),
1078  "1 ZB",
1079  "1 zetabyte"
1080  ],
1081  [
1082  pow( 1024, 8 ),
1083  "1 YB",
1084  "1 yottabyte"
1085  ],
1086  // How big!? THIS BIG!
1087  ];
1088  }
1089 
1094  public function testFormatBitrate( $bps, $expected, $msg ) {
1095  $this->assertEquals(
1096  $expected,
1097  $this->getLang()->formatBitrate( $bps ),
1098  "formatBitrate('$bps'): $msg"
1099  );
1100  }
1101 
1102  public static function provideFormatBitrate() {
1103  return [
1104  [
1105  0,
1106  "0 bps",
1107  "0 bits per second"
1108  ],
1109  [
1110  999,
1111  "999 bps",
1112  "999 bits per second"
1113  ],
1114  [
1115  1000,
1116  "1 kbps",
1117  "1 kilobit per second"
1118  ],
1119  [
1120  1000 * 1000,
1121  "1 Mbps",
1122  "1 megabit per second"
1123  ],
1124  [
1125  pow( 10, 9 ),
1126  "1 Gbps",
1127  "1 gigabit per second"
1128  ],
1129  [
1130  pow( 10, 12 ),
1131  "1 Tbps",
1132  "1 terabit per second"
1133  ],
1134  [
1135  pow( 10, 15 ),
1136  "1 Pbps",
1137  "1 petabit per second"
1138  ],
1139  [
1140  pow( 10, 18 ),
1141  "1 Ebps",
1142  "1 exabit per second"
1143  ],
1144  [
1145  pow( 10, 21 ),
1146  "1 Zbps",
1147  "1 zetabit per second"
1148  ],
1149  [
1150  pow( 10, 24 ),
1151  "1 Ybps",
1152  "1 yottabit per second"
1153  ],
1154  [
1155  pow( 10, 27 ),
1156  "1,000 Ybps",
1157  "1,000 yottabits per second"
1158  ],
1159  ];
1160  }
1161 
1166  public function testFormatDuration( $duration, $expected, $intervals = [] ) {
1167  $this->assertEquals(
1168  $expected,
1169  $this->getLang()->formatDuration( $duration, $intervals ),
1170  "formatDuration('$duration'): $expected"
1171  );
1172  }
1173 
1174  public static function provideFormatDuration() {
1175  return [
1176  [
1177  0,
1178  '0 seconds',
1179  ],
1180  [
1181  1,
1182  '1 second',
1183  ],
1184  [
1185  2,
1186  '2 seconds',
1187  ],
1188  [
1189  60,
1190  '1 minute',
1191  ],
1192  [
1193  2 * 60,
1194  '2 minutes',
1195  ],
1196  [
1197  3600,
1198  '1 hour',
1199  ],
1200  [
1201  2 * 3600,
1202  '2 hours',
1203  ],
1204  [
1205  24 * 3600,
1206  '1 day',
1207  ],
1208  [
1209  2 * 86400,
1210  '2 days',
1211  ],
1212  [
1213  // ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952
1214  ( 365 + ( 24 * 3 + 25 ) / 400.0 ) * 86400,
1215  '1 year',
1216  ],
1217  [
1218  2 * 31556952,
1219  '2 years',
1220  ],
1221  [
1222  10 * 31556952,
1223  '1 decade',
1224  ],
1225  [
1226  20 * 31556952,
1227  '2 decades',
1228  ],
1229  [
1230  100 * 31556952,
1231  '1 century',
1232  ],
1233  [
1234  200 * 31556952,
1235  '2 centuries',
1236  ],
1237  [
1238  1000 * 31556952,
1239  '1 millennium',
1240  ],
1241  [
1242  2000 * 31556952,
1243  '2 millennia',
1244  ],
1245  [
1246  9001,
1247  '2 hours, 30 minutes and 1 second'
1248  ],
1249  [
1250  3601,
1251  '1 hour and 1 second'
1252  ],
1253  [
1254  31556952 + 2 * 86400 + 9000,
1255  '1 year, 2 days, 2 hours and 30 minutes'
1256  ],
1257  [
1258  42 * 1000 * 31556952 + 42,
1259  '42 millennia and 42 seconds'
1260  ],
1261  [
1262  60,
1263  '60 seconds',
1264  [ 'seconds' ],
1265  ],
1266  [
1267  61,
1268  '61 seconds',
1269  [ 'seconds' ],
1270  ],
1271  [
1272  1,
1273  '1 second',
1274  [ 'seconds' ],
1275  ],
1276  [
1277  31556952 + 2 * 86400 + 9000,
1278  '1 year, 2 days and 150 minutes',
1279  [ 'years', 'days', 'minutes' ],
1280  ],
1281  [
1282  42,
1283  '0 days',
1284  [ 'years', 'days' ],
1285  ],
1286  [
1287  31556952 + 2 * 86400 + 9000,
1288  '1 year, 2 days and 150 minutes',
1289  [ 'minutes', 'days', 'years' ],
1290  ],
1291  [
1292  42,
1293  '0 days',
1294  [ 'days', 'years' ],
1295  ],
1296  ];
1297  }
1298 
1303  public function testCheckTitleEncoding( $s ) {
1304  $this->assertEquals(
1305  $s,
1306  $this->getLang()->checkTitleEncoding( $s ),
1307  "checkTitleEncoding('$s')"
1308  );
1309  }
1310 
1311  public static function provideCheckTitleEncodingData() {
1312  // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
1313  return [
1314  [ "" ],
1315  [ "United States of America" ], // 7bit ASCII
1316  [ rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ],
1317  [
1318  rawurldecode(
1319  "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
1320  )
1321  ],
1322  // The following two data sets come from bug 36839. They fail if checkTitleEncoding uses a regexp to test for
1323  // valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
1324  // uses mb_check_encoding for its test.
1325  [
1326  rawurldecode(
1327  "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
1328  . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
1329  . "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C"
1330  . "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C"
1331  . "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C"
1332  . "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C"
1333  . "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C"
1334  . "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C"
1335  . "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C"
1336  . "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C"
1337  . "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C"
1338  . "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C"
1339  . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
1340  . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
1341  ),
1342  ],
1343  [
1344  rawurldecode(
1345  "Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
1346  . "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
1347  . "Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C"
1348  . "Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C"
1349  . "Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou"
1350  . "%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C"
1351  . "Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C"
1352  . "Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C"
1353  . "Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C"
1354  . "Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C"
1355  . "Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C"
1356  . "Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C"
1357  . "Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C"
1358  . "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
1359  . "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
1360  )
1361  ]
1362  ];
1363  // @codingStandardsIgnoreEnd
1364  }
1365 
1370  public function testRomanNumerals( $num, $numerals ) {
1371  $this->assertEquals(
1372  $numerals,
1373  Language::romanNumeral( $num ),
1374  "romanNumeral('$num')"
1375  );
1376  }
1377 
1378  public static function provideRomanNumeralsData() {
1379  return [
1380  [ 1, 'I' ],
1381  [ 2, 'II' ],
1382  [ 3, 'III' ],
1383  [ 4, 'IV' ],
1384  [ 5, 'V' ],
1385  [ 6, 'VI' ],
1386  [ 7, 'VII' ],
1387  [ 8, 'VIII' ],
1388  [ 9, 'IX' ],
1389  [ 10, 'X' ],
1390  [ 20, 'XX' ],
1391  [ 30, 'XXX' ],
1392  [ 40, 'XL' ],
1393  [ 49, 'XLIX' ],
1394  [ 50, 'L' ],
1395  [ 60, 'LX' ],
1396  [ 70, 'LXX' ],
1397  [ 80, 'LXXX' ],
1398  [ 90, 'XC' ],
1399  [ 99, 'XCIX' ],
1400  [ 100, 'C' ],
1401  [ 200, 'CC' ],
1402  [ 300, 'CCC' ],
1403  [ 400, 'CD' ],
1404  [ 500, 'D' ],
1405  [ 600, 'DC' ],
1406  [ 700, 'DCC' ],
1407  [ 800, 'DCCC' ],
1408  [ 900, 'CM' ],
1409  [ 999, 'CMXCIX' ],
1410  [ 1000, 'M' ],
1411  [ 1989, 'MCMLXXXIX' ],
1412  [ 2000, 'MM' ],
1413  [ 3000, 'MMM' ],
1414  [ 4000, 'MMMM' ],
1415  [ 5000, 'MMMMM' ],
1416  [ 6000, 'MMMMMM' ],
1417  [ 7000, 'MMMMMMM' ],
1418  [ 8000, 'MMMMMMMM' ],
1419  [ 9000, 'MMMMMMMMM' ],
1420  [ 9999, 'MMMMMMMMMCMXCIX' ],
1421  [ 10000, 'MMMMMMMMMM' ],
1422  ];
1423  }
1424 
1429  public function testHebrewNumeral( $num, $numerals ) {
1430  $this->assertEquals(
1431  $numerals,
1432  Language::hebrewNumeral( $num ),
1433  "hebrewNumeral('$num')"
1434  );
1435  }
1436 
1437  public static function provideHebrewNumeralsData() {
1438  return [
1439  [ -1, -1 ],
1440  [ 0, 0 ],
1441  [ 1, "א'" ],
1442  [ 2, "ב'" ],
1443  [ 3, "ג'" ],
1444  [ 4, "ד'" ],
1445  [ 5, "ה'" ],
1446  [ 6, "ו'" ],
1447  [ 7, "ז'" ],
1448  [ 8, "ח'" ],
1449  [ 9, "ט'" ],
1450  [ 10, "י'" ],
1451  [ 11, 'י"א' ],
1452  [ 14, 'י"ד' ],
1453  [ 15, 'ט"ו' ],
1454  [ 16, 'ט"ז' ],
1455  [ 17, 'י"ז' ],
1456  [ 20, "כ'" ],
1457  [ 21, 'כ"א' ],
1458  [ 30, "ל'" ],
1459  [ 40, "מ'" ],
1460  [ 50, "נ'" ],
1461  [ 60, "ס'" ],
1462  [ 70, "ע'" ],
1463  [ 80, "פ'" ],
1464  [ 90, "צ'" ],
1465  [ 99, 'צ"ט' ],
1466  [ 100, "ק'" ],
1467  [ 101, 'ק"א' ],
1468  [ 110, 'ק"י' ],
1469  [ 200, "ר'" ],
1470  [ 300, "ש'" ],
1471  [ 400, "ת'" ],
1472  [ 500, 'ת"ק' ],
1473  [ 800, 'ת"ת' ],
1474  [ 1000, "א' אלף" ],
1475  [ 1001, "א'א'" ],
1476  [ 1012, "א'י\"ב" ],
1477  [ 1020, "א'ך'" ],
1478  [ 1030, "א'ל'" ],
1479  [ 1081, "א'פ\"א" ],
1480  [ 2000, "ב' אלפים" ],
1481  [ 2016, "ב'ט\"ז" ],
1482  [ 3000, "ג' אלפים" ],
1483  [ 4000, "ד' אלפים" ],
1484  [ 4904, "ד'תתק\"ד" ],
1485  [ 5000, "ה' אלפים" ],
1486  [ 5680, "ה'תר\"ף" ],
1487  [ 5690, "ה'תר\"ץ" ],
1488  [ 5708, "ה'תש\"ח" ],
1489  [ 5720, "ה'תש\"ך" ],
1490  [ 5740, "ה'תש\"ם" ],
1491  [ 5750, "ה'תש\"ן" ],
1492  [ 5775, "ה'תשע\"ה" ],
1493  ];
1494  }
1495 
1500  public function testConvertPlural( $expected, $number, $forms ) {
1501  $chosen = $this->getLang()->convertPlural( $number, $forms );
1502  $this->assertEquals( $expected, $chosen );
1503  }
1504 
1505  public static function providePluralData() {
1506  // Params are: [expected text, number given, [the plural forms]]
1507  return [
1508  [ 'plural', 0, [
1509  'singular', 'plural'
1510  ] ],
1511  [ 'explicit zero', 0, [
1512  '0=explicit zero', 'singular', 'plural'
1513  ] ],
1514  [ 'explicit one', 1, [
1515  'singular', 'plural', '1=explicit one',
1516  ] ],
1517  [ 'singular', 1, [
1518  'singular', 'plural', '0=explicit zero',
1519  ] ],
1520  [ 'plural', 3, [
1521  '0=explicit zero', '1=explicit one', 'singular', 'plural'
1522  ] ],
1523  [ 'explicit eleven', 11, [
1524  'singular', 'plural', '11=explicit eleven',
1525  ] ],
1526  [ 'plural', 12, [
1527  'singular', 'plural', '11=explicit twelve',
1528  ] ],
1529  [ 'plural', 12, [
1530  'singular', 'plural', '=explicit form',
1531  ] ],
1532  [ 'other', 2, [
1533  'kissa=kala', '1=2=3', 'other',
1534  ] ],
1535  [ '', 2, [
1536  '0=explicit zero', '1=explicit one',
1537  ] ],
1538  ];
1539  }
1540 
1544  public function testEmbedBidi() {
1545  $lre = "\xE2\x80\xAA"; // U+202A LEFT-TO-RIGHT EMBEDDING
1546  $rle = "\xE2\x80\xAB"; // U+202B RIGHT-TO-LEFT EMBEDDING
1547  $pdf = "\xE2\x80\xAC"; // U+202C POP DIRECTIONAL FORMATTING
1548  $lang = $this->getLang();
1549  $this->assertEquals(
1550  '123',
1551  $lang->embedBidi( '123' ),
1552  'embedBidi with neutral argument'
1553  );
1554  $this->assertEquals(
1555  $lre . 'Ben_(WMF)' . $pdf,
1556  $lang->embedBidi( 'Ben_(WMF)' ),
1557  'embedBidi with LTR argument'
1558  );
1559  $this->assertEquals(
1560  $rle . 'יהודי (מנוחין)' . $pdf,
1561  $lang->embedBidi( 'יהודי (מנוחין)' ),
1562  'embedBidi with RTL argument'
1563  );
1564  }
1565 
1570  public function testTranslateBlockExpiry( $expectedData, $str, $desc ) {
1571  $lang = $this->getLang();
1572  if ( is_array( $expectedData ) ) {
1573  list( $func, $arg ) = $expectedData;
1574  $expected = $lang->$func( $arg );
1575  } else {
1576  $expected = $expectedData;
1577  }
1578  $this->assertEquals( $expected, $lang->translateBlockExpiry( $str ), $desc );
1579  }
1580 
1581  public static function provideTranslateBlockExpiry() {
1582  return [
1583  [ '2 hours', '2 hours', 'simple data from ipboptions' ],
1584  [ 'indefinite', 'infinite', 'infinite from ipboptions' ],
1585  [ 'indefinite', 'infinity', 'alternative infinite from ipboptions' ],
1586  [ 'indefinite', 'indefinite', 'another alternative infinite from ipboptions' ],
1587  [ [ 'formatDuration', 1023 * 60 * 60 ], '1023 hours', 'relative' ],
1588  [ [ 'formatDuration', -1023 ], '-1023 seconds', 'negative relative' ],
1589  [ [ 'formatDuration', 0 ], 'now', 'now' ],
1590  [
1591  [ 'timeanddate', '20120102070000' ],
1592  '2012-1-1 7:00 +1 day',
1593  'mixed, handled as absolute'
1594  ],
1595  [ [ 'timeanddate', '19910203040506' ], '1991-2-3 4:05:06', 'absolute' ],
1596  [ [ 'timeanddate', '19700101000000' ], '1970-1-1 0:00:00', 'absolute at epoch' ],
1597  [ [ 'timeanddate', '19691231235959' ], '1969-12-31 23:59:59', 'time before epoch' ],
1598  [ 'dummy', 'dummy', 'return garbage as is' ],
1599  ];
1600  }
1601 
1605  public function testParseFormattedNumber( $langCode, $number ) {
1606  $lang = Language::factory( $langCode );
1607 
1608  $localisedNum = $lang->formatNum( $number );
1609  $normalisedNum = $lang->parseFormattedNumber( $localisedNum );
1610 
1611  $this->assertEquals( $number, $normalisedNum );
1612  }
1613 
1614  public function parseFormattedNumberProvider() {
1615  return [
1616  [ 'de', 377.01 ],
1617  [ 'fa', 334 ],
1618  [ 'fa', 382.772 ],
1619  [ 'ar', 1844 ],
1620  [ 'lzh', 3731 ],
1621  [ 'zh-classical', 7432 ]
1622  ];
1623  }
1624 
1629  public function testCommafy( $number, $numbersWithCommas ) {
1630  $this->assertEquals(
1631  $numbersWithCommas,
1632  $this->getLang()->commafy( $number ),
1633  "commafy('$number')"
1634  );
1635  }
1636 
1637  public static function provideCommafyData() {
1638  return [
1639  [ -1, '-1' ],
1640  [ 10, '10' ],
1641  [ 100, '100' ],
1642  [ 1000, '1,000' ],
1643  [ 10000, '10,000' ],
1644  [ 100000, '100,000' ],
1645  [ 1000000, '1,000,000' ],
1646  [ -1.0001, '-1.0001' ],
1647  [ 1.0001, '1.0001' ],
1648  [ 10.0001, '10.0001' ],
1649  [ 100.0001, '100.0001' ],
1650  [ 1000.0001, '1,000.0001' ],
1651  [ 10000.0001, '10,000.0001' ],
1652  [ 100000.0001, '100,000.0001' ],
1653  [ 1000000.0001, '1,000,000.0001' ],
1654  [ '200000000000000000000', '200,000,000,000,000,000,000' ],
1655  [ '-200000000000000000000', '-200,000,000,000,000,000,000' ],
1656  ];
1657  }
1658 
1662  public function testListToText() {
1663  $lang = $this->getLang();
1664  $and = $lang->getMessageFromDB( 'and' );
1665  $s = $lang->getMessageFromDB( 'word-separator' );
1666  $c = $lang->getMessageFromDB( 'comma-separator' );
1667 
1668  $this->assertEquals( '', $lang->listToText( [] ) );
1669  $this->assertEquals( 'a', $lang->listToText( [ 'a' ] ) );
1670  $this->assertEquals( "a{$and}{$s}b", $lang->listToText( [ 'a', 'b' ] ) );
1671  $this->assertEquals( "a{$c}b{$and}{$s}c", $lang->listToText( [ 'a', 'b', 'c' ] ) );
1672  $this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( [ 'a', 'b', 'c', 'd' ] ) );
1673  }
1674 
1679  public function testIsSupportedLanguage( $code, $expected, $comment ) {
1680  $this->assertEquals( $expected, Language::isSupportedLanguage( $code ), $comment );
1681  }
1682 
1683  public static function provideIsSupportedLanguage() {
1684  return [
1685  [ 'en', true, 'is supported language' ],
1686  [ 'fi', true, 'is supported language' ],
1687  [ 'bunny', false, 'is not supported language' ],
1688  [ 'FI', false, 'is not supported language, input should be in lower case' ],
1689  ];
1690  }
1691 
1696  public function testGetParentLanguage( $code, $expected, $comment ) {
1698  if ( is_null( $expected ) ) {
1699  $this->assertNull( $lang->getParentLanguage(), $comment );
1700  } else {
1701  $this->assertEquals( $expected, $lang->getParentLanguage()->getCode(), $comment );
1702  }
1703  }
1704 
1705  public static function provideGetParentLanguage() {
1706  return [
1707  [ 'zh-cn', 'zh', 'zh is the parent language of zh-cn' ],
1708  [ 'zh', 'zh', 'zh is defined as the parent language of zh, '
1709  . 'because zh converter can convert zh-cn to zh' ],
1710  [ 'zh-invalid', null, 'do not be fooled by arbitrarily composed language codes' ],
1711  [ 'en-gb', null, 'en does not have converter' ],
1712  [ 'en', null, 'en does not have converter. Although FakeConverter '
1713  . 'handles en -> en conversion but it is useless' ],
1714  ];
1715  }
1716 
1721  public function testGetNamespaceAliases( $languageCode, $subset ) {
1722  $language = Language::factory( $languageCode );
1723  $aliases = $language->getNamespaceAliases();
1724  foreach ( $subset as $alias => $nsId ) {
1725  $this->assertEquals( $nsId, $aliases[$alias] );
1726  }
1727  }
1728 
1729  public static function provideGetNamespaceAliases() {
1730  // TODO: Add tests for NS_PROJECT_TALK and GenderNamespaces
1731  return [
1732  [
1733  'zh',
1734  [
1735  '文件' => NS_FILE,
1736  '檔案' => NS_FILE,
1737  ],
1738  ],
1739  ];
1740  }
1741 }
testSprintfDateTooShortTimestamp()
Test too short timestamp MWException Language::sprintfDate.
testFormatSize($size, $expected, $msg)
provideFormatSizes Language::formatSize
parseFormattedNumberProvider()
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
static isKnownLanguageTag($tag)
Returns true if a language code is an IETF tag known to MediaWiki.
Definition: Language.php:381
testTranslateBlockExpiry($expectedData, $str, $desc)
Language::translateBlockExpiry() provideTranslateBlockExpiry.
static provideSprintfDateSamples()
testFormatTimePeriod($seconds, $format, $expected, $desc)
provideFormattableTimes Language::formatTimePeriod
testFormatBitrate($bps, $expected, $msg)
provideFormatBitrate Language::formatBitrate
static providePluralData()
static isWellFormedLanguageTag($code, $lenient=false)
Returns true if a language code string is a well-formed language tag according to RFC 5646...
Definition: Language.php:279
static provideUnknownLanguageTags()
testMalformedLanguageTag($code, $message= '')
Negative test for Language::isWellFormedLanguageTag() provideMalformedLanguageTags Language::isWellFo...
testLanguageConvertDoubleWidthToSingleWidth()
Language::convertDoubleWidth Language::normalizeForSearch.
Definition: LanguageTest.php:8
testBuiltInCodeValidation($code, $expected, $message= '')
Test Language::isValidBuiltInCode() provideLanguageCodes Language::isValidBuiltInCode.
if(!isset($args[0])) $lang
$comment
testSprintfDateNoZone($format, $ts, $expected, $ignore, $msg)
sprintfDate should always use UTC when no zone is given.
static provideHTMLTruncateData()
static provideCommafyData()
testSprintfDateNotAllDigitTimestamp()
Test too short timestamp MWException Language::sprintfDate.
testGetNamespaceAliases($languageCode, $subset)
provideGetNamespaceAliases Language::getNamespaceAliases
testFormatDuration($duration, $expected, $intervals=[])
provideFormatDuration Language::formatDuration
testEmbedBidi()
Language::embedBidi()
static provideHebrewNumeralsData()
testLenientLanguageTag()
Negative test for Language::isWellFormedLanguageTag() Language::isWellFormedLanguageTag.
static provideMalformedLanguageTags()
The test cases are based on the tests in the GaBuZoMeu parser written by Stéphane Bortzmeyer bortzmey...
static provideLanguageCodes()
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1798
testCommafy($number, $numbersWithCommas)
Language::commafy() provideCommafyData.
testListToText()
Language::listToText.
static provideKnownLanguageTags()
static provideTranslateBlockExpiry()
testSprintfDate($format, $ts, $expected, $msg)
provideSprintfDateSamples Language::sprintfDate
static hebrewNumeral($num)
Hebrew Gematria number formatting up to 9999.
Definition: Language.php:1981
$res
Definition: database.txt:21
testConvertPlural($expected, $number, $forms)
providePluralData Language::convertPlural
static isValidBuiltInCode($code)
Returns true if a language code is of a valid form for the purposes of internal customisation of Medi...
Definition: Language.php:358
testSprintfDateTZ($format, $ts, $ignore, $expected, $msg)
sprintfDate should use passed timezone provideSprintfDateSamples Language::sprintfDate ...
static provideGetNamespaceAliases()
testIsSupportedLanguage($code, $expected, $comment)
provideIsSupportedLanguage Language::isSupportedLanguage
const NS_FILE
Definition: Defines.php:75
testCheckTitleEncoding($s)
provideCheckTitleEncodingData Language::checkTitleEncoding
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
Definition: hooks.txt:762
testTruncateHtml($len, $ellipsis, $input, $expected)
provideHTMLTruncateData Language::truncateHTML
testKnownLanguageTag($code, $message= '')
Test Language::isKnownLanguageTag() provideKnownLanguageTags Language::isKnownLanguageTag.
testKnownCldrLanguageTag()
Language::isKnownLanguageTag.
testParseFormattedNumber($langCode, $number)
parseFormattedNumberProvider
testGetParentLanguage($code, $expected, $comment)
provideGetParentLanguage Language::getParentLanguage
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
static provideRomanNumeralsData()
static romanNumeral($num)
Roman number formatting up to 10000.
Definition: Language.php:1950
testWellFormedLanguageTag($code, $message= '')
Test Language::isWellFormedLanguageTag() provideWellFormedLanguageTags Language::isWellFormedLanguage...
static provideFormatDuration()
static provideGetParentLanguage()
static provideFormattableTimes()
testUnknownLanguageTag($code, $message= '')
Negative tests for Language::isKnownLanguageTag() provideUnKnownLanguageTags Language::isKnownLanguag...
static provideFormatBitrate()
testHebrewNumeral($num, $numerals)
provideHebrewNumeralsData Language::hebrewNumeral
static provideFormatSizes()
testRomanNumerals($num, $numerals)
provideRomanNumeralsData Language::romanNumeral
testSprintfDateTooLongTimestamp()
Test too long timestamp MWException Language::sprintfDate.
static factory($code)
Get a cached or new language object for a given language code.
Definition: Language.php:179
static provideCheckTitleEncodingData()
Helping class to run tests using a clean language instance.
static isSupportedLanguage($code)
Checks whether any localisation is available for that language tag in MediaWiki (MessagesXx.php exists).
Definition: Language.php:251
static provideIsSupportedLanguage()
testTruncate()
Language::truncate.
static provideWellFormedLanguageTags()
The test cases are based on the tests in the GaBuZoMeu parser written by Stéphane Bortzmeyer bortzmey...