Add 'api' type to extension types for special version
[lhc/web/wiklou.git] / tests / phpunit / includes / GlobalTest.php
index d9116dc..b06dbf1 100644 (file)
@@ -1,20 +1,48 @@
 <?php
 
-class GlobalTest extends PHPUnit_Framework_TestCase {
+class GlobalTest extends MediaWikiTestCase {
        function setUp() {
-               global $wgReadOnlyFile, $wgContLang, $wgLang;
+               global $wgReadOnlyFile, $wgContLang, $wgLang, $wgUrlProtocols, $wgLanguageCode;
                $this->originals['wgReadOnlyFile'] = $wgReadOnlyFile;
+               $this->originals['wgUrlProtocols'] = $wgUrlProtocols;
                $wgReadOnlyFile = tempnam( wfTempDir(), "mwtest_readonly" );
+               $wgUrlProtocols[] = 'file://';
                unlink( $wgReadOnlyFile );
+               $wgLanguageCode = 'en';
                $wgContLang = $wgLang = Language::factory( 'en' );
        }
 
        function tearDown() {
-               global $wgReadOnlyFile;
+               global $wgReadOnlyFile, $wgUrlProtocols;
                if ( file_exists( $wgReadOnlyFile ) ) {
                        unlink( $wgReadOnlyFile );
                }
                $wgReadOnlyFile = $this->originals['wgReadOnlyFile'];
+               $wgUrlProtocols = $this->originals['wgUrlProtocols'];
+       }
+
+       /** @dataProvider provideForWfArrayDiff2 */
+       public function testWfArrayDiff2( $a, $b, $expected ) {
+               $this->assertEquals(
+                       wfArrayDiff2( $a, $b), $expected
+               );
+       }
+
+       // @todo Provide more tests
+       public function provideForWfArrayDiff2() {
+               // $a $b $expected
+               return array(
+                       array(
+                               array( 'a', 'b'),
+                               array( 'a', 'b'),
+                               array(),
+                       ),
+                       array(
+                               array( array( 'a'), array( 'a', 'b', 'c' )),
+                               array( array( 'a'), array( 'a', 'b' )),
+                               array( 1 => array( 'a', 'b', 'c' ) ),
+                       ),
+               );
        }
 
        function testRandom() {
@@ -43,13 +71,13 @@ class GlobalTest extends PHPUnit_Framework_TestCase {
                $f = fopen( $wgReadOnlyFile, "wt" );
                fwrite( $f, 'Message' );
                fclose( $f );
-               $wgReadOnly = null;
+               $wgReadOnly = null; # Check on $wgReadOnlyFile
 
                $this->assertTrue( wfReadOnly() );
-               $this->assertTrue( wfReadOnly() );
+               $this->assertTrue( wfReadOnly() ); # Check cached
 
                unlink( $wgReadOnlyFile );
-               $wgReadOnly = null;
+               $wgReadOnly = null; # Clean cache
 
                $this->assertFalse( wfReadOnly() );
                $this->assertFalse( wfReadOnly() );
@@ -63,7 +91,7 @@ class GlobalTest extends PHPUnit_Framework_TestCase {
 
        function testTime() {
                $start = wfTime();
-               $this->assertType( 'float', $start );
+               $this->assertInternalType( 'float', $start );
                $end = wfTime();
                $this->assertTrue( $end > $start, "Time is running backwards!" );
        }
@@ -74,6 +102,18 @@ class GlobalTest extends PHPUnit_Framework_TestCase {
                        wfArrayToCGI(
                                array( 'baz' => 'AT&T', 'ignore' => '' ),
                                array( 'foo' => 'bar', 'baz' => 'overridden value' ) ) );
+               $this->assertEquals(
+                       "path%5B0%5D=wiki&path%5B1%5D=test&cfg%5Bservers%5D%5Bhttp%5D=localhost",
+                       wfArrayToCGI( array(
+                               'path' => array( 'wiki', 'test' ),
+                               'cfg' => array( 'servers' => array( 'http' => 'localhost' ) ) ) ) );
+       }
+
+       function testCgiToArray() {
+               $this->assertEquals(
+                       array( 'path' => array( 'wiki', 'test' ),
+                       'cfg' => array( 'servers' => array( 'http' => 'localhost' ) ) ),
+                       wfCgiToArray( 'path%5B0%5D=wiki&path%5B1%5D=test&cfg%5Bservers%5D%5Bhttp%5D=localhost' ) );
        }
 
        function testMimeTypeMatch() {
@@ -300,7 +340,7 @@ class GlobalTest extends PHPUnit_Framework_TestCase {
                        wfTimestamp( TS_RFC2822, '0117-08-09 12:34:56'),
                        'Death of Roman Emperor [[Trajan]]');
 
-               /* FIXME: 00 to 101 years are taken as being in [1970-2069] */
+               /* @todo FIXME: 00 to 101 years are taken as being in [1970-2069] */
 
                $this->assertEquals( 'Sun, 01 Jan 0101 00:00:00 GMT',
                        wfTimestamp( TS_RFC2822, '-58979923200'),
@@ -348,6 +388,27 @@ class GlobalTest extends PHPUnit_Framework_TestCase {
 
        }
 
+       function testTimestampParameter() {
+               // There are a number of assumptions in our codebase where wfTimestamp() should give 
+               // the current date but it is not given a 0 there. See r71751 CR
+
+               $now = wfTimestamp( TS_UNIX );
+               // We check that wfTimestamp doesn't return false (error) and use a LessThan assert 
+               // for the cases where the test is run in a second boundary.
+               
+               $zero = wfTimestamp( TS_UNIX, 0 );
+               $this->assertNotEquals( false, $zero );
+               $this->assertLessThan( 5, $zero - $now );
+
+               $empty = wfTimestamp( TS_UNIX, '' );
+               $this->assertNotEquals( false, $empty );
+               $this->assertLessThan( 5, $empty - $now );
+
+               $null = wfTimestamp( TS_UNIX, null );
+               $this->assertNotEquals( false, $null );
+               $this->assertLessThan( 5, $null - $now );
+       }
+
        function testBasename() {
                $sets = array(
                        '' => '',
@@ -373,8 +434,462 @@ class GlobalTest extends PHPUnit_Framework_TestCase {
                                "wfBaseName('$from') => '$to'" );
                }
        }
+       
+       
+       function testFallbackMbstringFunctions() {
+               
+               if( !extension_loaded( 'mbstring' ) ) {
+                       $this->markTestSkipped( "The mb_string functions must be installed to test the fallback functions" );
+               }
+               
+               $sampleUTF = "Östergötland_coat_of_arms.png";
+               
+               
+               //mb_substr
+               $substr_params = array(
+                       array( 0, 0 ),
+                       array( 5, -4 ),
+                       array( 33 ),
+                       array( 100, -5 ),
+                       array( -8, 10 ),
+                       array( 1, 1 ),
+                       array( 2, -1 )
+               );
+               
+               foreach( $substr_params as $param_set ) {
+                       $old_param_set = $param_set;
+                       array_unshift( $param_set, $sampleUTF );
+                       
+                       $this->assertEquals(
+                               MWFunction::callArray( 'mb_substr', $param_set ),
+                               MWFunction::callArray( 'Fallback::mb_substr', $param_set ),
+                               'Fallback mb_substr with params ' . implode( ', ', $old_param_set )
+                       );                      
+               }
+               
+               
+               //mb_strlen
+               $this->assertEquals(
+                       mb_strlen( $sampleUTF ),
+                       Fallback::mb_strlen( $sampleUTF ),
+                       'Fallback mb_strlen'
+               );                      
+               
+               
+               //mb_str(r?)pos
+               $strpos_params = array(
+                       //array( 'ter' ),
+                       //array( 'Ö' ),
+                       //array( 'Ö', 3 ),
+                       //array( 'oat_', 100 ),
+                       //array( 'c', -10 ),
+                       //Broken for now
+               );
+               
+               foreach( $strpos_params as $param_set ) {
+                       $old_param_set = $param_set;
+                       array_unshift( $param_set, $sampleUTF );
+                       
+                       $this->assertEquals(
+                               MWFunction::callArray( 'mb_strpos', $param_set ),
+                               MWFunction::callArray( 'Fallback::mb_strpos', $param_set ),
+                               'Fallback mb_strpos with params ' . implode( ', ', $old_param_set )
+                       );              
+                       
+                       $this->assertEquals(
+                               MWFunction::callArray( 'mb_strrpos', $param_set ),
+                               MWFunction::callArray( 'Fallback::mb_strrpos', $param_set ),
+                               'Fallback mb_strrpos with params ' . implode( ', ', $old_param_set )
+                       );      
+               }
+               
+       }
+       
+       
+       function testDebugFunctionTest() {
+       
+               global $wgDebugLogFile, $wgOut, $wgShowDebug, $wgDebugTimestamps;
+               
+               $old_log_file = $wgDebugLogFile;
+               $wgDebugLogFile = tempnam( wfTempDir(), 'mw-' );
+               # @todo FIXME: This setting should be tested
+               $wgDebugTimestamps = false;
+               
+               
+               
+               wfDebug( "This is a normal string" );
+               $this->assertEquals( "This is a normal string", file_get_contents( $wgDebugLogFile ) );
+               unlink( $wgDebugLogFile );
+               
+               
+               wfDebug( "This is nöt an ASCII string" );
+               $this->assertEquals( "This is nöt an ASCII string", file_get_contents( $wgDebugLogFile ) );
+               unlink( $wgDebugLogFile );
+               
+               
+               wfDebug( "\00305This has böth UTF and control chars\003" );
+               $this->assertEquals( " 05This has böth UTF and control chars ", file_get_contents( $wgDebugLogFile ) );
+               unlink( $wgDebugLogFile );
+               
+               
+               
+               $old_wgOut = $wgOut;
+               $old_wgShowDebug = $wgShowDebug;
+               
+               $wgOut = new MockOutputPage;
+               
+               $wgShowDebug = true;
+               
+               $message = "\00305This has böth UTF and control chars\003";
+               
+               wfDebug( $message );
+               
+               if( $wgOut->message == "JAJA is a stupid error message. Anyway, here's your message: $message" ) {
+                       $this->assertTrue( true, 'MockOutputPage called, set the proper message.' );
+               }
+               else {
+                       $this->assertTrue( false, 'MockOutputPage was not called.' );
+               }
+               
+               $wgOut = $old_wgOut;
+               $wgShowDebug = $old_wgShowDebug;                
+               unlink( $wgDebugLogFile );
+               
+               
+               
+               wfDebugMem();
+               $this->assertGreaterThan( 5000, preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) );
+               unlink( $wgDebugLogFile );
+               
+               wfDebugMem(true);
+               $this->assertGreaterThan( 5000000, preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) );
+               unlink( $wgDebugLogFile );
+               
+               
+               
+               $wgDebugLogFile = $old_log_file;
+               
+       }
+       
+       function testClientAcceptsGzipTest() {
+               
+               $settings = array(
+                       'gzip' => true,
+                       'bzip' => false,
+                       '*' => false,
+                       'compress, gzip' => true,
+                       'gzip;q=1.0' => true,
+                       'foozip' => false,
+                       'foo*zip' => false,
+                       'gzip;q=abcde' => true, //is this REALLY valid?
+                       'gzip;q=12345678.9' => true,
+                       ' gzip' => true,
+               );
+               
+               if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) $old_server_setting = $_SERVER['HTTP_ACCEPT_ENCODING'];
+               
+               foreach ( $settings as $encoding => $expect ) {
+                       $_SERVER['HTTP_ACCEPT_ENCODING'] = $encoding;
+                       
+                       $this->assertEquals( $expect, wfClientAcceptsGzip( true ),
+                               "'$encoding' => " . wfBoolToStr( $expect ) );
+               }
+               
+               if( isset( $old_server_setting ) ) $_SERVER['HTTP_ACCEPT_ENCODING'] = $old_server_setting;
+
+       }
+       
+       
+       
+       function testSwapVarsTest() {
+       
+
+               $var1 = 1;
+               $var2 = 2;
+
+               $this->assertEquals( $var1, 1, 'var1 is set originally' );
+               $this->assertEquals( $var2, 2, 'var1 is set originally' );
+
+               swap( $var1, $var2 );
+
+               $this->assertEquals( $var1, 2, 'var1 is swapped' );
+               $this->assertEquals( $var2, 1, 'var2 is swapped' );
+
+       }
+
+
+       function testWfPercentTest() {
+
+               $pcts = array(
+                       array( 6/7, '0.86%', 2, false ),
+                       array( 3/3, '1%' ),
+                       array( 22/7, '3.14286%', 5 ),
+                       array( 3/6, '0.5%' ),
+                       array( 1/3, '0%', 0 ),
+                       array( 10/3, '0%', -1 ),
+                       array( 3/4/5, '0.1%', 1 ),
+                       array( 6/7*8, '6.8571428571%', 10 ),
+               );
+               
+               foreach( $pcts as $pct ) {
+                       if( !isset( $pct[2] ) ) $pct[2] = 2;
+                       if( !isset( $pct[3] ) ) $pct[3] = true;
+                       
+                       $this->assertEquals( wfPercent( $pct[0], $pct[2], $pct[3] ), $pct[1], $pct[1] );
+               }
+
+       }
+
+
+       function testInStringTest() {
+       
+               $this->assertTrue( in_string( 'foo', 'foobar' ), 'foo is in foobar' );
+               $this->assertFalse( in_string( 'Bar', 'foobar' ), 'Case-sensitive by default' );
+               $this->assertTrue( in_string( 'Foo', 'foobar', true ), 'Case-insensitive when asked' );
+       
+       }
+
+       /**
+        * test @see wfShorthandToInteger()
+        * @dataProvider provideShorthand
+        */
+       public function testWfShorthandToInteger( $shorthand, $expected ) {
+               $this->assertEquals( $expected,
+                       wfShorthandToInteger( $shorthand )
+               );      
+       }
+
+       /** array( shorthand, expected integer ) */
+       public function provideShorthand() {
+               return array(
+                       # Null, empty ... 
+                       array(     '', -1),
+                       array(   '  ', -1),
+                       array(   null, -1),
+
+                       # Failures returns 0 :(
+                       array( 'ABCDEFG', 0 ),
+                       array( 'Ak',      0 ),
+
+                       # Int, strings with spaces
+                       array(        1,    1 ),
+                       array(    ' 1 ',    1 ),
+                       array(     1023, 1023 ),
+                       array( ' 1023 ', 1023 ),
+
+                       # kilo, Mega, Giga
+                       array(   '1k', 1024 ),
+                       array(   '1K', 1024 ),
+                       array(   '1m', 1024 * 1024 ),
+                       array(   '1M', 1024 * 1024 ),
+                       array(   '1g', 1024 * 1024 * 1024 ),
+                       array(   '1G', 1024 * 1024 * 1024 ),
+
+                       # Negatives
+                       array(     -1,    -1 ),
+                       array(   -500,  -500 ),
+                       array( '-500',  -500 ),
+                       array(  '-1k', -1024 ),
+
+                       # Zeroes
+                       array(   '0', 0 ),
+                       array(  '0k', 0 ),
+                       array(  '0M', 0 ),
+                       array(  '0G', 0 ),
+                       array(  '-0', 0 ),
+                       array( '-0k', 0 ),
+                       array( '-0M', 0 ),
+                       array( '-0G', 0 ),
+               );
+       }
+
+
+       /**
+        * test @see wfBCP47().
+        * Please note the BCP explicitly state that language codes are case
+        * insensitive, there are some exceptions to the rule :)
+        * This test is used to verify our formatting against all lower and
+        * all upper cases language code.
+        *
+        * @see http://tools.ietf.org/html/bcp47
+        * @dataProvider provideLanguageCodes()
+        */
+       function testBCP47( $code, $expected ) {
+               $code = strtolower( $code );
+               $this->assertEquals( $expected, wfBCP47($code),
+                       "Applying BCP47 standard to lower case '$code'"
+               );
+
+               $code = strtoupper( $code );
+               $this->assertEquals( $expected, wfBCP47($code),
+                       "Applying BCP47 standard to upper case '$code'"
+               );
+       }
+
+       /**
+        * Array format is ($code, $expected)
+        */
+       function provideLanguageCodes() {
+               return array(
+                       // Extracted from BCP47 (list not exhaustive)
+                       # 2.1.1
+                       array( 'en-ca-x-ca'    , 'en-CA-x-ca'     ),
+                       array( 'sgn-be-fr'     , 'sgn-BE-FR'      ),
+                       array( 'az-latn-x-latn', 'az-Latn-x-latn' ),
+                       # 2.2
+                       array( 'sr-Latn-RS', 'sr-Latn-RS' ),
+                       array( 'az-arab-ir', 'az-Arab-IR' ),
+
+                       # 2.2.5
+                       array( 'sl-nedis'  , 'sl-nedis'   ),
+                       array( 'de-ch-1996', 'de-CH-1996' ),
+
+                       # 2.2.6
+                       array(
+                               'en-latn-gb-boont-r-extended-sequence-x-private',
+                               'en-Latn-GB-boont-r-extended-sequence-x-private'
+                       ),
+
+                       // Examples from BCP47 Appendix A
+                       # Simple language subtag:
+                       array( 'DE', 'de' ),
+                       array( 'fR', 'fr' ),
+                       array( 'ja', 'ja' ),
+
+                       # Language subtag plus script subtag:
+                       array( 'zh-hans', 'zh-Hans'),
+                       array( 'sr-cyrl', 'sr-Cyrl'),
+                       array( 'sr-latn', 'sr-Latn'),
+
+                       # Extended language subtags and their primary language subtag
+                       # counterparts:
+                       array( 'zh-cmn-hans-cn', 'zh-cmn-Hans-CN' ),
+                       array( 'cmn-hans-cn'   , 'cmn-Hans-CN'    ),
+                       array( 'zh-yue-hk'     , 'zh-yue-HK'      ),
+                       array( 'yue-hk'        , 'yue-HK'         ),
+
+                       # Language-Script-Region:
+                       array( 'zh-hans-cn', 'zh-Hans-CN' ),
+                       array( 'sr-latn-RS', 'sr-Latn-RS' ),
+
+                       # Language-Variant:
+                       array( 'sl-rozaj'      , 'sl-rozaj'       ),
+                       array( 'sl-rozaj-biske', 'sl-rozaj-biske' ),
+                       array( 'sl-nedis'      , 'sl-nedis'       ),
+
+                       # Language-Region-Variant:
+                       array( 'de-ch-1901'  , 'de-CH-1901'  ),
+                       array( 'sl-it-nedis' , 'sl-IT-nedis' ),
+
+                       # Language-Script-Region-Variant:
+                       array( 'hy-latn-it-arevela', 'hy-Latn-IT-arevela' ),
+
+                       # Language-Region:
+                       array( 'de-de' , 'de-DE' ),
+                       array( 'en-us' , 'en-US' ),
+                       array( 'es-419', 'es-419'),
+
+                       # Private use subtags:
+                       array( 'de-ch-x-phonebk'      , 'de-CH-x-phonebk' ),
+                       array( 'az-arab-x-aze-derbend', 'az-Arab-x-aze-derbend' ),
+                       /**
+                        * Previous test does not reflect the BCP which states:
+                        *  az-Arab-x-AZE-derbend
+                        * AZE being private, it should be lower case, hence the test above
+                        * should probably be:
+                       #array( 'az-arab-x-aze-derbend', 'az-Arab-x-AZE-derbend' ),
+                        */
+
+                       # Private use registry values:
+                       array( 'x-whatever', 'x-whatever' ),
+                       array( 'qaa-qaaa-qm-x-southern', 'qaa-Qaaa-QM-x-southern' ),
+                       array( 'de-qaaa'   , 'de-Qaaa'    ),
+                       array( 'sr-latn-qm', 'sr-Latn-QM' ),
+                       array( 'sr-qaaa-rs', 'sr-Qaaa-RS' ),
+
+                       # Tags that use extensions
+                       array( 'en-us-u-islamcal', 'en-US-u-islamcal' ),
+                       array( 'zh-cn-a-myext-x-private', 'zh-CN-a-myext-x-private' ),
+                       array( 'en-a-myext-b-another', 'en-a-myext-b-another' ),
+
+                       # Invalid:
+                       // de-419-DE
+                       // a-DE
+                       // ar-a-aaa-b-bbb-a-ccc
+       
+               /*      
+                       // ISO 15924 :
+                       array( 'sr-Cyrl', 'sr-Cyrl' ),
+                       # @todo FIXME: Fix our function?
+                       array( 'SR-lATN', 'sr-Latn' ),
+                       array( 'fr-latn', 'fr-Latn' ),
+                       // Use lowercase for single segment
+                       // ISO 3166-1-alpha-2 code
+                       array( 'US', 'us' ),  # USA
+                       array( 'uS', 'us' ),  # USA
+                       array( 'Fr', 'fr' ),  # France
+                       array( 'va', 'va' ),  # Holy See (Vatican City State)
+                */);
+       }
+
+       /**
+        * @dataProvider provideMakeUrlIndex()
+        */
+       function testMakeUrlIndex( $url, $expected ) {
+               $index = wfMakeUrlIndex( $url );
+               $this->assertEquals( $expected, $index, "wfMakeUrlIndex(\"$url\")" );
+       }
+
+       function provideMakeUrlIndex() {
+               return array(
+                       array(
+                               // just a regular :)
+                               'https://bugzilla.wikimedia.org/show_bug.cgi?id=28627',
+                               'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627'
+                       ),
+                       array(
+                               // mailtos are handled special
+                               // is this really right though? that final . probably belongs earlier?
+                               'mailto:wiki@wikimedia.org',
+                               'mailto:org.wikimedia@wiki.',
+                       ),
+
+                       // file URL cases per bug 28627...
+                       array(
+                               // three slashes: local filesystem path Unix-style
+                               'file:///whatever/you/like.txt',
+                               'file://./whatever/you/like.txt'
+                       ),
+                       array(
+                               // three slashes: local filesystem path Windows-style
+                               'file:///c:/whatever/you/like.txt',
+                               'file://./c:/whatever/you/like.txt'
+                       ),
+                       array(
+                               // two slashes: UNC filesystem path Windows-style
+                               'file://intranet/whatever/you/like.txt',
+                               'file://intranet./whatever/you/like.txt'
+                       ),
+                       // Multiple-slash cases that can sorta work on Mozilla
+                       // if you hack it just right are kinda pathological,
+                       // and unreliable cross-platform or on IE which means they're
+                       // unlikely to appear on intranets.
+                       //
+                       // Those will survive the algorithm but with results that
+                       // are less consistent.
+               );
+       }
 
        /* TODO: many more! */
 }
 
 
+class MockOutputPage {
+       
+       public $message;
+       
+       function debug( $message ) {
+               $this->message = "JAJA is a stupid error message. Anyway, here's your message: $message";
+       }
+}
+