summaryrefslogtreecommitdiff
path: root/www/wiki/tests/phpunit/includes/GlobalFunctions
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/tests/phpunit/includes/GlobalFunctions')
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/GlobalTest.php812
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php32
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/README2
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php79
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php42
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php94
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php112
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php40
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php43
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php117
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfGetCallerTest.php46
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfParseUrlTest.php157
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php93
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfShellExecTest.php20
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php31
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfStringToBoolTest.php51
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php105
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php194
-rw-r--r--www/wiki/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php125
19 files changed, 2195 insertions, 0 deletions
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
new file mode 100644
index 00000000..ee4819fa
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
@@ -0,0 +1,812 @@
+<?php
+
+/**
+ * @group Database
+ * @group GlobalFunctions
+ */
+class GlobalTest extends MediaWikiTestCase {
+ protected function setUp() {
+ parent::setUp();
+
+ $readOnlyFile = $this->getNewTempFile();
+ unlink( $readOnlyFile );
+
+ $this->setMwGlobals( [
+ 'wgReadOnlyFile' => $readOnlyFile,
+ 'wgUrlProtocols' => [
+ 'http://',
+ 'https://',
+ 'mailto:',
+ '//',
+ 'file://', # Non-default
+ ],
+ ] );
+ }
+
+ /**
+ * @dataProvider provideForWfArrayDiff2
+ * @covers ::wfArrayDiff2
+ */
+ public function testWfArrayDiff2( $a, $b, $expected ) {
+ $this->assertEquals(
+ wfArrayDiff2( $a, $b ), $expected
+ );
+ }
+
+ // @todo Provide more tests
+ public static function provideForWfArrayDiff2() {
+ // $a $b $expected
+ return [
+ [
+ [ 'a', 'b' ],
+ [ 'a', 'b' ],
+ [],
+ ],
+ [
+ [ [ 'a' ], [ 'a', 'b', 'c' ] ],
+ [ [ 'a' ], [ 'a', 'b' ] ],
+ [ 1 => [ 'a', 'b', 'c' ] ],
+ ],
+ ];
+ }
+
+ /*
+ * Test cases for random functions could hypothetically fail,
+ * even though they shouldn't.
+ */
+
+ /**
+ * @covers ::wfRandom
+ */
+ public function testRandom() {
+ $this->assertFalse(
+ wfRandom() == wfRandom()
+ );
+ }
+
+ /**
+ * @covers ::wfRandomString
+ */
+ public function testRandomString() {
+ $this->assertFalse(
+ wfRandomString() == wfRandomString()
+ );
+ $this->assertEquals(
+ strlen( wfRandomString( 10 ) ), 10
+ );
+ $this->assertTrue(
+ preg_match( '/^[0-9a-f]+$/i', wfRandomString() ) === 1
+ );
+ }
+
+ /**
+ * @covers ::wfUrlencode
+ */
+ public function testUrlencode() {
+ $this->assertEquals(
+ "%E7%89%B9%E5%88%A5:Contributions/Foobar",
+ wfUrlencode( "\xE7\x89\xB9\xE5\x88\xA5:Contributions/Foobar" ) );
+ }
+
+ /**
+ * @covers ::wfExpandIRI
+ */
+ public function testExpandIRI() {
+ $this->assertEquals(
+ "https://te.wikibooks.org/wiki/ఉబుంటు_వాడుకరి_మార్గదర్శని",
+ wfExpandIRI( "https://te.wikibooks.org/wiki/"
+ . "%E0%B0%89%E0%B0%AC%E0%B1%81%E0%B0%82%E0%B0%9F%E0%B1%81_"
+ . "%E0%B0%B5%E0%B0%BE%E0%B0%A1%E0%B1%81%E0%B0%95%E0%B0%B0%E0%B0%BF_"
+ . "%E0%B0%AE%E0%B0%BE%E0%B0%B0%E0%B1%8D%E0%B0%97%E0%B0%A6%E0%B0%B0"
+ . "%E0%B1%8D%E0%B0%B6%E0%B0%A8%E0%B0%BF" ) );
+ }
+
+ /**
+ * Intended to cover the relevant bits of ServiceWiring.php, as well as GlobalFunctions.php
+ * @covers ::wfReadOnly
+ */
+ public function testReadOnlyEmpty() {
+ global $wgReadOnly;
+ $wgReadOnly = null;
+
+ MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()->clearCache();
+ $this->assertFalse( wfReadOnly() );
+ $this->assertFalse( wfReadOnly() );
+ }
+
+ /**
+ * Intended to cover the relevant bits of ServiceWiring.php, as well as GlobalFunctions.php
+ * @covers ::wfReadOnly
+ */
+ public function testReadOnlySet() {
+ global $wgReadOnly, $wgReadOnlyFile;
+
+ $readOnlyMode = MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
+ $readOnlyMode->clearCache();
+
+ $f = fopen( $wgReadOnlyFile, "wt" );
+ fwrite( $f, 'Message' );
+ fclose( $f );
+ $wgReadOnly = null; # Check on $wgReadOnlyFile
+
+ $this->assertTrue( wfReadOnly() );
+ $this->assertTrue( wfReadOnly() ); # Check cached
+
+ unlink( $wgReadOnlyFile );
+ $readOnlyMode->clearCache();
+ $this->assertFalse( wfReadOnly() );
+ $this->assertFalse( wfReadOnly() );
+ }
+
+ /**
+ * This behaviour could probably be deprecated. Several extensions rely on it as of 1.29.
+ * @covers ::wfReadOnlyReason
+ */
+ public function testReadOnlyGlobalChange() {
+ $this->assertFalse( wfReadOnlyReason() );
+ $this->setMwGlobals( [
+ 'wgReadOnly' => 'reason'
+ ] );
+ $this->assertSame( 'reason', wfReadOnlyReason() );
+ }
+
+ public static function provideArrayToCGI() {
+ return [
+ [ [], '' ], // empty
+ [ [ 'foo' => 'bar' ], 'foo=bar' ], // string test
+ [ [ 'foo' => '' ], 'foo=' ], // empty string test
+ [ [ 'foo' => 1 ], 'foo=1' ], // number test
+ [ [ 'foo' => true ], 'foo=1' ], // true test
+ [ [ 'foo' => false ], '' ], // false test
+ [ [ 'foo' => null ], '' ], // null test
+ [ [ 'foo' => 'A&B=5+6@!"\'' ], 'foo=A%26B%3D5%2B6%40%21%22%27' ], // urlencoding test
+ [
+ [ 'foo' => 'bar', 'baz' => 'is', 'asdf' => 'qwerty' ],
+ 'foo=bar&baz=is&asdf=qwerty'
+ ], // multi-item test
+ [ [ 'foo' => [ 'bar' => 'baz' ] ], 'foo%5Bbar%5D=baz' ],
+ [
+ [ 'foo' => [ 'bar' => 'baz', 'qwerty' => 'asdf' ] ],
+ 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf'
+ ],
+ [ [ 'foo' => [ 'bar', 'baz' ] ], 'foo%5B0%5D=bar&foo%5B1%5D=baz' ],
+ [
+ [ 'foo' => [ 'bar' => [ 'bar' => 'baz' ] ] ],
+ 'foo%5Bbar%5D%5Bbar%5D=baz'
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideArrayToCGI
+ * @covers ::wfArrayToCgi
+ */
+ public function testArrayToCGI( $array, $result ) {
+ $this->assertEquals( $result, wfArrayToCgi( $array ) );
+ }
+
+ /**
+ * @covers ::wfArrayToCgi
+ */
+ public function testArrayToCGI2() {
+ $this->assertEquals(
+ "baz=bar&foo=bar",
+ wfArrayToCgi(
+ [ 'baz' => 'bar' ],
+ [ 'foo' => 'bar', 'baz' => 'overridden value' ] ) );
+ }
+
+ public static function provideCgiToArray() {
+ return [
+ [ '', [] ], // empty
+ [ 'foo=bar', [ 'foo' => 'bar' ] ], // string
+ [ 'foo=', [ 'foo' => '' ] ], // empty string
+ [ 'foo', [ 'foo' => '' ] ], // missing =
+ [ 'foo=bar&qwerty=asdf', [ 'foo' => 'bar', 'qwerty' => 'asdf' ] ], // multiple value
+ [ 'foo=A%26B%3D5%2B6%40%21%22%27', [ 'foo' => 'A&B=5+6@!"\'' ] ], // urldecoding test
+ [ 'foo%5Bbar%5D=baz', [ 'foo' => [ 'bar' => 'baz' ] ] ],
+ [
+ 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf',
+ [ 'foo' => [ 'bar' => 'baz', 'qwerty' => 'asdf' ] ]
+ ],
+ [ 'foo%5B0%5D=bar&foo%5B1%5D=baz', [ 'foo' => [ 0 => 'bar', 1 => 'baz' ] ] ],
+ [
+ 'foo%5Bbar%5D%5Bbar%5D=baz',
+ [ 'foo' => [ 'bar' => [ 'bar' => 'baz' ] ] ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideCgiToArray
+ * @covers ::wfCgiToArray
+ */
+ public function testCgiToArray( $cgi, $result ) {
+ $this->assertEquals( $result, wfCgiToArray( $cgi ) );
+ }
+
+ public static function provideCgiRoundTrip() {
+ return [
+ [ '' ],
+ [ 'foo=bar' ],
+ [ 'foo=' ],
+ [ 'foo=bar&baz=biz' ],
+ [ 'foo=A%26B%3D5%2B6%40%21%22%27' ],
+ [ 'foo%5Bbar%5D=baz' ],
+ [ 'foo%5B0%5D=bar&foo%5B1%5D=baz' ],
+ [ 'foo%5Bbar%5D%5Bbar%5D=baz' ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideCgiRoundTrip
+ * @covers ::wfArrayToCgi
+ */
+ public function testCgiRoundTrip( $cgi ) {
+ $this->assertEquals( $cgi, wfArrayToCgi( wfCgiToArray( $cgi ) ) );
+ }
+
+ /**
+ * @covers ::mimeTypeMatch
+ */
+ public function testMimeTypeMatch() {
+ $this->assertEquals(
+ 'text/html',
+ mimeTypeMatch( 'text/html',
+ [ 'application/xhtml+xml' => 1.0,
+ 'text/html' => 0.7,
+ 'text/plain' => 0.3 ] ) );
+ $this->assertEquals(
+ 'text/*',
+ mimeTypeMatch( 'text/html',
+ [ 'image/*' => 1.0,
+ 'text/*' => 0.5 ] ) );
+ $this->assertEquals(
+ '*/*',
+ mimeTypeMatch( 'text/html',
+ [ '*/*' => 1.0 ] ) );
+ $this->assertNull(
+ mimeTypeMatch( 'text/html',
+ [ 'image/png' => 1.0,
+ 'image/svg+xml' => 0.5 ] ) );
+ }
+
+ /**
+ * @covers ::wfNegotiateType
+ */
+ public function testNegotiateType() {
+ $this->assertEquals(
+ 'text/html',
+ wfNegotiateType(
+ [ 'application/xhtml+xml' => 1.0,
+ 'text/html' => 0.7,
+ 'text/plain' => 0.5,
+ 'text/*' => 0.2 ],
+ [ 'text/html' => 1.0 ] ) );
+ $this->assertEquals(
+ 'application/xhtml+xml',
+ wfNegotiateType(
+ [ 'application/xhtml+xml' => 1.0,
+ 'text/html' => 0.7,
+ 'text/plain' => 0.5,
+ 'text/*' => 0.2 ],
+ [ 'application/xhtml+xml' => 1.0,
+ 'text/html' => 0.5 ] ) );
+ $this->assertEquals(
+ 'text/html',
+ wfNegotiateType(
+ [ 'text/html' => 1.0,
+ 'text/plain' => 0.5,
+ 'text/*' => 0.5,
+ 'application/xhtml+xml' => 0.2 ],
+ [ 'application/xhtml+xml' => 1.0,
+ 'text/html' => 0.5 ] ) );
+ $this->assertEquals(
+ 'text/html',
+ wfNegotiateType(
+ [ 'text/*' => 1.0,
+ 'image/*' => 0.7,
+ '*/*' => 0.3 ],
+ [ 'application/xhtml+xml' => 1.0,
+ 'text/html' => 0.5 ] ) );
+ $this->assertNull(
+ wfNegotiateType(
+ [ 'text/*' => 1.0 ],
+ [ 'application/xhtml+xml' => 1.0 ] ) );
+ }
+
+ /**
+ * @covers ::wfDebug
+ * @covers ::wfDebugMem
+ */
+ public function testDebugFunctionTest() {
+ $debugLogFile = $this->getNewTempFile();
+
+ $this->setMwGlobals( [
+ 'wgDebugLogFile' => $debugLogFile,
+ #  @todo FIXME: $wgDebugTimestamps should be tested
+ 'wgDebugTimestamps' => false
+ ] );
+
+ wfDebug( "This is a normal string" );
+ $this->assertEquals( "This is a normal string\n", file_get_contents( $debugLogFile ) );
+ unlink( $debugLogFile );
+
+ wfDebug( "This is nöt an ASCII string" );
+ $this->assertEquals( "This is nöt an ASCII string\n", file_get_contents( $debugLogFile ) );
+ unlink( $debugLogFile );
+
+ wfDebug( "\00305This has böth UTF and control chars\003" );
+ $this->assertEquals(
+ " 05This has böth UTF and control chars \n",
+ file_get_contents( $debugLogFile )
+ );
+ unlink( $debugLogFile );
+
+ wfDebugMem();
+ $this->assertGreaterThan(
+ 1000,
+ preg_replace( '/\D/', '', file_get_contents( $debugLogFile ) )
+ );
+ unlink( $debugLogFile );
+
+ wfDebugMem( true );
+ $this->assertGreaterThan(
+ 1000000,
+ preg_replace( '/\D/', '', file_get_contents( $debugLogFile ) )
+ );
+ unlink( $debugLogFile );
+ }
+
+ /**
+ * @covers ::wfClientAcceptsGzip
+ */
+ public function testClientAcceptsGzipTest() {
+ $settings = [
+ '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;
+ }
+ }
+
+ /**
+ * @covers ::wfPercent
+ */
+ public function testWfPercentTest() {
+ $pcts = [
+ [ 6 / 7, '0.86%', 2, false ],
+ [ 3 / 3, '1%' ],
+ [ 22 / 7, '3.14286%', 5 ],
+ [ 3 / 6, '0.5%' ],
+ [ 1 / 3, '0%', 0 ],
+ [ 10 / 3, '0%', -1 ],
+ [ 3 / 4 / 5, '0.1%', 1 ],
+ [ 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] );
+ }
+ }
+
+ /**
+ * test @see wfShorthandToInteger()
+ * @dataProvider provideShorthand
+ * @covers ::wfShorthandToInteger
+ */
+ public function testWfShorthandToInteger( $shorthand, $expected ) {
+ $this->assertEquals( $expected,
+ wfShorthandToInteger( $shorthand )
+ );
+ }
+
+ public static function provideShorthand() {
+ // Syntax: [ shorthand, expected integer ]
+ return [
+ # Null, empty ...
+ [ '', -1 ],
+ [ ' ', -1 ],
+ [ null, -1 ],
+
+ # Failures returns 0 :(
+ [ 'ABCDEFG', 0 ],
+ [ 'Ak', 0 ],
+
+ # Int, strings with spaces
+ [ 1, 1 ],
+ [ ' 1 ', 1 ],
+ [ 1023, 1023 ],
+ [ ' 1023 ', 1023 ],
+
+ # kilo, Mega, Giga
+ [ '1k', 1024 ],
+ [ '1K', 1024 ],
+ [ '1m', 1024 * 1024 ],
+ [ '1M', 1024 * 1024 ],
+ [ '1g', 1024 * 1024 * 1024 ],
+ [ '1G', 1024 * 1024 * 1024 ],
+
+ # Negatives
+ [ -1, -1 ],
+ [ -500, -500 ],
+ [ '-500', -500 ],
+ [ '-1k', -1024 ],
+
+ # Zeroes
+ [ '0', 0 ],
+ [ '0k', 0 ],
+ [ '0M', 0 ],
+ [ '0G', 0 ],
+ [ '-0', 0 ],
+ [ '-0k', 0 ],
+ [ '-0M', 0 ],
+ [ '-0G', 0 ],
+ ];
+ }
+
+ /**
+ * @covers ::wfMerge
+ */
+ public function testMerge_worksWithLessParameters() {
+ $this->markTestSkippedIfNoDiff3();
+
+ $mergedText = null;
+ $successfulMerge = wfMerge( "old1\n\nold2", "old1\n\nnew2", "new1\n\nold2", $mergedText );
+
+ $mergedText = null;
+ $conflictingMerge = wfMerge( 'old', 'old and mine', 'old and yours', $mergedText );
+
+ $this->assertEquals( true, $successfulMerge );
+ $this->assertEquals( false, $conflictingMerge );
+ }
+
+ /**
+ * @param string $old Text as it was in the database
+ * @param string $mine Text submitted while user was editing
+ * @param string $yours Text submitted by the user
+ * @param bool $expectedMergeResult Whether the merge should be a success
+ * @param string $expectedText Text after merge has been completed
+ * @param string $expectedMergeAttemptResult Diff3 output if conflicts occur
+ *
+ * @dataProvider provideMerge()
+ * @group medium
+ * @covers ::wfMerge
+ */
+ public function testMerge( $old, $mine, $yours, $expectedMergeResult, $expectedText,
+ $expectedMergeAttemptResult ) {
+ $this->markTestSkippedIfNoDiff3();
+
+ $mergedText = null;
+ $attemptMergeResult = null;
+ $isMerged = wfMerge( $old, $mine, $yours, $mergedText, $mergeAttemptResult );
+
+ $msg = 'Merge should be a ';
+ $msg .= $expectedMergeResult ? 'success' : 'failure';
+ $this->assertEquals( $expectedMergeResult, $isMerged, $msg );
+ $this->assertEquals( $expectedMergeAttemptResult, $mergeAttemptResult );
+
+ if ( $isMerged ) {
+ // Verify the merged text
+ $this->assertEquals( $expectedText, $mergedText,
+ 'is merged text as expected?' );
+ }
+ }
+
+ public static function provideMerge() {
+ $EXPECT_MERGE_SUCCESS = true;
+ $EXPECT_MERGE_FAILURE = false;
+
+ return [
+ // #0: clean merge
+ [
+ // old:
+ "one one one\n" . // trimmed
+ "\n" .
+ "two two two",
+
+ // mine:
+ "one one one ONE ONE\n" .
+ "\n" .
+ "two two two\n", // with tailing whitespace
+
+ // yours:
+ "one one one\n" .
+ "\n" .
+ "two two TWO TWO", // trimmed
+
+ // ok:
+ $EXPECT_MERGE_SUCCESS,
+
+ // result:
+ "one one one ONE ONE\n" .
+ "\n" .
+ "two two TWO TWO\n", // note: will always end in a newline
+
+ // mergeAttemptResult:
+ "",
+ ],
+
+ // #1: conflict, fail
+ [
+ // old:
+ "one one one", // trimmed
+
+ // mine:
+ "one one one ONE ONE\n" .
+ "\n" .
+ "bla bla\n" .
+ "\n", // with tailing whitespace
+
+ // yours:
+ "one one one\n" .
+ "\n" .
+ "two two", // trimmed
+
+ $EXPECT_MERGE_FAILURE,
+
+ // result:
+ null,
+
+ // mergeAttemptResult:
+ "1,3c\n" .
+ "one one one\n" .
+ "\n" .
+ "two two\n" .
+ ".\n",
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideMakeUrlIndexes()
+ * @covers ::wfMakeUrlIndexes
+ */
+ public function testMakeUrlIndexes( $url, $expected ) {
+ $index = wfMakeUrlIndexes( $url );
+ $this->assertEquals( $expected, $index, "wfMakeUrlIndexes(\"$url\")" );
+ }
+
+ public static function provideMakeUrlIndexes() {
+ return [
+ // Testcase for T30627
+ [
+ 'https://example.org/test.cgi?id=12345',
+ [ 'https://org.example./test.cgi?id=12345' ]
+ ],
+ [
+ // 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 T30627...
+ [
+ // three slashes: local filesystem path Unix-style
+ 'file:///whatever/you/like.txt',
+ [ 'file://./whatever/you/like.txt' ]
+ ],
+ [
+ // three slashes: local filesystem path Windows-style
+ 'file:///c:/whatever/you/like.txt',
+ [ 'file://./c:/whatever/you/like.txt' ]
+ ],
+ [
+ // 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.
+
+ // protocol-relative URL cases per T31854...
+ [
+ '//example.org/test.cgi?id=12345',
+ [
+ 'http://org.example./test.cgi?id=12345',
+ 'https://org.example./test.cgi?id=12345'
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideWfMatchesDomainList
+ * @covers ::wfMatchesDomainList
+ */
+ public function testWfMatchesDomainList( $url, $domains, $expected, $description ) {
+ $actual = wfMatchesDomainList( $url, $domains );
+ $this->assertEquals( $expected, $actual, $description );
+ }
+
+ public static function provideWfMatchesDomainList() {
+ $a = [];
+ $protocols = [ 'HTTP' => 'http:', 'HTTPS' => 'https:', 'protocol-relative' => '' ];
+ foreach ( $protocols as $pDesc => $p ) {
+ $a = array_merge( $a, [
+ [
+ "$p//www.example.com",
+ [],
+ false,
+ "No matches for empty domains array, $pDesc URL"
+ ],
+ [
+ "$p//www.example.com",
+ [ 'www.example.com' ],
+ true,
+ "Exact match in domains array, $pDesc URL"
+ ],
+ [
+ "$p//www.example.com",
+ [ 'example.com' ],
+ true,
+ "Match without subdomain in domains array, $pDesc URL"
+ ],
+ [
+ "$p//www.example2.com",
+ [ 'www.example.com', 'www.example2.com', 'www.example3.com' ],
+ true,
+ "Exact match with other domains in array, $pDesc URL"
+ ],
+ [
+ "$p//www.example2.com",
+ [ 'example.com', 'example2.com', 'example3,com' ],
+ true,
+ "Match without subdomain with other domains in array, $pDesc URL"
+ ],
+ [
+ "$p//www.example4.com",
+ [ 'example.com', 'example2.com', 'example3,com' ],
+ false,
+ "Domain not in array, $pDesc URL"
+ ],
+ [
+ "$p//nds-nl.wikipedia.org",
+ [ 'nl.wikipedia.org' ],
+ false,
+ "Non-matching substring of domain, $pDesc URL"
+ ],
+ ] );
+ }
+
+ return $a;
+ }
+
+ /**
+ * @covers ::wfMkdirParents
+ */
+ public function testWfMkdirParents() {
+ // Should not return true if file exists instead of directory
+ $fname = $this->getNewTempFile();
+ Wikimedia\suppressWarnings();
+ $ok = wfMkdirParents( $fname );
+ Wikimedia\restoreWarnings();
+ $this->assertFalse( $ok );
+ }
+
+ /**
+ * @dataProvider provideWfShellWikiCmdList
+ * @covers ::wfShellWikiCmd
+ */
+ public function testWfShellWikiCmd( $script, $parameters, $options,
+ $expected, $description
+ ) {
+ if ( wfIsWindows() ) {
+ // Approximation that's good enough for our purposes just now
+ $expected = str_replace( "'", '"', $expected );
+ }
+ $actual = wfShellWikiCmd( $script, $parameters, $options );
+ $this->assertEquals( $expected, $actual, $description );
+ }
+
+ public function wfWikiID() {
+ $this->setMwGlobals( [
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => '',
+ ] );
+ $this->assertEquals(
+ wfWikiID(),
+ 'example'
+ );
+
+ $this->setMwGlobals( [
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => 'mw_',
+ ] );
+ $this->assertEquals(
+ wfWikiID(),
+ 'example-mw_'
+ );
+ }
+
+ /**
+ * @covers ::wfMemcKey
+ */
+ public function testWfMemcKey() {
+ $cache = ObjectCache::getLocalClusterInstance();
+ $this->assertEquals(
+ $cache->makeKey( 'foo', 123, 'bar' ),
+ wfMemcKey( 'foo', 123, 'bar' )
+ );
+ }
+
+ /**
+ * @covers ::wfForeignMemcKey
+ */
+ public function testWfForeignMemcKey() {
+ $cache = ObjectCache::getLocalClusterInstance();
+ $keyspace = $this->readAttribute( $cache, 'keyspace' );
+ $this->assertEquals(
+ wfForeignMemcKey( $keyspace, '', 'foo', 'bar' ),
+ $cache->makeKey( 'foo', 'bar' )
+ );
+ }
+
+ /**
+ * @covers ::wfGlobalCacheKey
+ */
+ public function testWfGlobalCacheKey() {
+ $cache = ObjectCache::getLocalClusterInstance();
+ $this->assertEquals(
+ $cache->makeGlobalKey( 'foo', 123, 'bar' ),
+ wfGlobalCacheKey( 'foo', 123, 'bar' )
+ );
+ }
+
+ public static function provideWfShellWikiCmdList() {
+ global $wgPhpCli;
+
+ return [
+ [ 'eval.php', [ '--help', '--test' ], [],
+ "'$wgPhpCli' 'eval.php' '--help' '--test'",
+ "Called eval.php --help --test" ],
+ [ 'eval.php', [ '--help', '--test space' ], [ 'php' => 'php5' ],
+ "'php5' 'eval.php' '--help' '--test space'",
+ "Called eval.php --help --test with php option" ],
+ [ 'eval.php', [ '--help', '--test', 'X' ], [ 'wrapper' => 'MWScript.php' ],
+ "'$wgPhpCli' 'MWScript.php' 'eval.php' '--help' '--test' 'X'",
+ "Called eval.php --help --test with wrapper option" ],
+ [
+ 'eval.php',
+ [ '--help', '--test', 'y' ],
+ [ 'php' => 'php5', 'wrapper' => 'MWScript.php' ],
+ "'php5' 'MWScript.php' 'eval.php' '--help' '--test' 'y'",
+ "Called eval.php --help --test with wrapper and php option"
+ ],
+ ];
+ }
+ /* @todo many more! */
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php
new file mode 100644
index 00000000..0765ab8b
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @group Database
+ */
+class GlobalWithDBTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideWfIsBadImageList
+ * @covers ::wfIsBadImage
+ */
+ public function testWfIsBadImage( $name, $title, $blacklist, $expected, $desc ) {
+ $this->assertEquals( $expected, wfIsBadImage( $name, $title, $blacklist ), $desc );
+ }
+
+ public static function provideWfIsBadImageList() {
+ $blacklist = '* [[File:Bad.jpg]] except [[Nasty page]]';
+
+ return [
+ [ 'Bad.jpg', false, $blacklist, true,
+ 'Called on a bad image' ],
+ [ 'Bad.jpg', Title::makeTitle( NS_MAIN, 'A page' ), $blacklist, true,
+ 'Called on a bad image' ],
+ [ 'NotBad.jpg', false, $blacklist, false,
+ 'Called on a non-bad image' ],
+ [ 'Bad.jpg', Title::makeTitle( NS_MAIN, 'Nasty page' ), $blacklist, false,
+ 'Called on a bad image but is on a whitelisted page' ],
+ [ 'File:Bad.jpg', false, $blacklist, false,
+ 'Called on a bad image with File:' ],
+ ];
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/README b/www/wiki/tests/phpunit/includes/GlobalFunctions/README
new file mode 100644
index 00000000..0042bdac
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/README
@@ -0,0 +1,2 @@
+This directory hold tests for includes/GlobalFunctions.php file
+which is a pile of functions.
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php
new file mode 100644
index 00000000..bb71610b
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfAppendQuery
+ */
+class WfAppendQueryTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideAppendQuery
+ */
+ public function testAppendQuery( $url, $query, $expected, $message = null ) {
+ $this->assertEquals( $expected, wfAppendQuery( $url, $query ), $message );
+ }
+
+ public static function provideAppendQuery() {
+ return [
+ [
+ 'http://www.example.org/index.php',
+ '',
+ 'http://www.example.org/index.php',
+ 'No query'
+ ],
+ [
+ 'http://www.example.org/index.php',
+ [ 'foo' => 'bar' ],
+ 'http://www.example.org/index.php?foo=bar',
+ 'Set query array'
+ ],
+ [
+ 'http://www.example.org/index.php?foz=baz',
+ 'foo=bar',
+ 'http://www.example.org/index.php?foz=baz&foo=bar',
+ 'Set query string'
+ ],
+ [
+ 'http://www.example.org/index.php?foo=bar',
+ '',
+ 'http://www.example.org/index.php?foo=bar',
+ 'Empty string with query'
+ ],
+ [
+ 'http://www.example.org/index.php?foo=bar',
+ [ 'baz' => 'quux' ],
+ 'http://www.example.org/index.php?foo=bar&baz=quux',
+ 'Add query array'
+ ],
+ [
+ 'http://www.example.org/index.php?foo=bar',
+ 'baz=quux',
+ 'http://www.example.org/index.php?foo=bar&baz=quux',
+ 'Add query string'
+ ],
+ [
+ 'http://www.example.org/index.php?foo=bar',
+ [ 'baz' => 'quux', 'foo' => 'baz' ],
+ 'http://www.example.org/index.php?foo=bar&baz=quux&foo=baz',
+ 'Modify query array'
+ ],
+ [
+ 'http://www.example.org/index.php?foo=bar',
+ 'baz=quux&foo=baz',
+ 'http://www.example.org/index.php?foo=bar&baz=quux&foo=baz',
+ 'Modify query string'
+ ],
+ [
+ 'http://www.example.org/index.php#baz',
+ 'foo=bar',
+ 'http://www.example.org/index.php?foo=bar#baz',
+ 'URL with fragment'
+ ],
+ [
+ 'http://www.example.org/index.php?foo=bar#baz',
+ 'quux=blah',
+ 'http://www.example.org/index.php?foo=bar&quux=blah#baz',
+ 'URL with query string and fragment'
+ ]
+ ];
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php
new file mode 100644
index 00000000..1011a37c
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfArrayFilterTest.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfArrayFilter
+ * @covers ::wfArrayFilterByKey
+ */
+class WfArrayFilterTest extends \PHPUnit\Framework\TestCase {
+ public function testWfArrayFilter() {
+ $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
+ $filtered = wfArrayFilter( $arr, function ( $val, $key ) {
+ return $key !== 'b';
+ } );
+ $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
+
+ $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
+ $filtered = wfArrayFilter( $arr, function ( $val, $key ) {
+ return $val !== 2;
+ } );
+ $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
+
+ $arr = [ 'a', 'b', 'c' ];
+ $filtered = wfArrayFilter( $arr, function ( $val, $key ) {
+ return $key !== 0;
+ } );
+ $this->assertSame( [ 1 => 'b', 2 => 'c' ], $filtered );
+ }
+
+ public function testWfArrayFilterByKey() {
+ $arr = [ 'a' => 1, 'b' => 2, 'c' => 3 ];
+ $filtered = wfArrayFilterByKey( $arr, function ( $key ) {
+ return $key !== 'b';
+ } );
+ $this->assertSame( [ 'a' => 1, 'c' => 3 ], $filtered );
+
+ $arr = [ 'a', 'b', 'c' ];
+ $filtered = wfArrayFilterByKey( $arr, function ( $key ) {
+ return $key !== 0;
+ } );
+ $this->assertSame( [ 1 => 'b', 2 => 'c' ], $filtered );
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php
new file mode 100644
index 00000000..65b56ef4
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * @group GlobalFunctions
+ * @covers ::wfArrayPlus2d
+ */
+class WfArrayPlus2dTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideArrays
+ */
+ public function testWfArrayPlus2d( $baseArray, $newValues, $expected, $testName ) {
+ $this->assertEquals(
+ $expected,
+ wfArrayPlus2d( $baseArray, $newValues ),
+ $testName
+ );
+ }
+
+ /**
+ * Provider for testing wfArrayPlus2d
+ *
+ * @return array
+ */
+ public static function provideArrays() {
+ return [
+ // target array, new values array, expected result
+ [
+ [ 0 => '1dArray' ],
+ [ 1 => '1dArray' ],
+ [ 0 => '1dArray', 1 => '1dArray' ],
+ "Test simple union of two arrays with different keys",
+ ],
+ [
+ [
+ 0 => [ 0 => '2dArray' ],
+ ],
+ [
+ 0 => [ 1 => '2dArray' ],
+ ],
+ [
+ 0 => [ 0 => '2dArray', 1 => '2dArray' ],
+ ],
+ "Test union of 2d arrays with different keys in the value array",
+ ],
+ [
+ [
+ 0 => [ 0 => '2dArray' ],
+ ],
+ [
+ 0 => [ 0 => '1dArray' ],
+ ],
+ [
+ 0 => [ 0 => '2dArray' ],
+ ],
+ "Test union of 2d arrays with same keys in the value array",
+ ],
+ [
+ [
+ 0 => [ 0 => [ 0 => '3dArray' ] ],
+ ],
+ [
+ 0 => [ 0 => [ 1 => '2dArray' ] ],
+ ],
+ [
+ 0 => [ 0 => [ 0 => '3dArray' ] ],
+ ],
+ "Test union of 3d array with different keys",
+ ],
+ [
+ [
+ 0 => [ 0 => [ 0 => '3dArray' ] ],
+ ],
+ [
+ 0 => [ 1 => [ 0 => '2dArray' ] ],
+ ],
+ [
+ 0 => [ 0 => [ 0 => '3dArray' ], 1 => [ 0 => '2dArray' ] ],
+ ],
+ "Test union of 3d array with different keys in the value array",
+ ],
+ [
+ [
+ 0 => [ 0 => [ 0 => '3dArray' ] ],
+ ],
+ [
+ 0 => [ 0 => [ 0 => '2dArray' ] ],
+ ],
+ [
+ 0 => [ 0 => [ 0 => '3dArray' ] ],
+ ],
+ "Test union of 3d array with same keys in the value array",
+ ],
+ ];
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php
new file mode 100644
index 00000000..7ddad369
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * @group GlobalFunctions
+ * @covers ::wfAssembleUrl
+ */
+class WfAssembleUrlTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideURLParts
+ */
+ public function testWfAssembleUrl( $parts, $output ) {
+ $partsDump = print_r( $parts, true );
+ $this->assertEquals(
+ $output,
+ wfAssembleUrl( $parts ),
+ "Testing $partsDump assembles to $output"
+ );
+ }
+
+ /**
+ * Provider of URL parts for testing wfAssembleUrl()
+ *
+ * @return array
+ */
+ public static function provideURLParts() {
+ $schemes = [
+ '' => [],
+ '//' => [
+ 'delimiter' => '//',
+ ],
+ 'http://' => [
+ 'scheme' => 'http',
+ 'delimiter' => '://',
+ ],
+ ];
+
+ $hosts = [
+ '' => [],
+ 'example.com' => [
+ 'host' => 'example.com',
+ ],
+ 'example.com:123' => [
+ 'host' => 'example.com',
+ 'port' => 123,
+ ],
+ 'id@example.com' => [
+ 'user' => 'id',
+ 'host' => 'example.com',
+ ],
+ 'id@example.com:123' => [
+ 'user' => 'id',
+ 'host' => 'example.com',
+ 'port' => 123,
+ ],
+ 'id:key@example.com' => [
+ 'user' => 'id',
+ 'pass' => 'key',
+ 'host' => 'example.com',
+ ],
+ 'id:key@example.com:123' => [
+ 'user' => 'id',
+ 'pass' => 'key',
+ 'host' => 'example.com',
+ 'port' => 123,
+ ],
+ ];
+
+ $cases = [];
+ foreach ( $schemes as $scheme => $schemeParts ) {
+ foreach ( $hosts as $host => $hostParts ) {
+ foreach ( [ '', '/path' ] as $path ) {
+ foreach ( [ '', 'query' ] as $query ) {
+ foreach ( [ '', 'fragment' ] as $fragment ) {
+ $parts = array_merge(
+ $schemeParts,
+ $hostParts
+ );
+ $url = $scheme .
+ $host .
+ $path;
+
+ if ( $path ) {
+ $parts['path'] = $path;
+ }
+ if ( $query ) {
+ $parts['query'] = $query;
+ $url .= '?' . $query;
+ }
+ if ( $fragment ) {
+ $parts['fragment'] = $fragment;
+ $url .= '#' . $fragment;
+ }
+
+ $cases[] = [
+ $parts,
+ $url,
+ ];
+ }
+ }
+ }
+ }
+ }
+
+ $complexURL = 'http://id:key@example.org:321' .
+ '/over/there?name=ferret&foo=bar#nose';
+ $cases[] = [
+ wfParseUrl( $complexURL ),
+ $complexURL,
+ ];
+
+ return $cases;
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php
new file mode 100644
index 00000000..78e09e60
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @group GlobalFunctions
+ * @covers ::wfBaseName
+ */
+class WfBaseNameTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider providePaths
+ */
+ public function testBaseName( $fullpath, $basename ) {
+ $this->assertEquals( $basename, wfBaseName( $fullpath ),
+ "wfBaseName('$fullpath') => '$basename'" );
+ }
+
+ public static function providePaths() {
+ return [
+ [ '', '' ],
+ [ '/', '' ],
+ [ '\\', '' ],
+ [ '//', '' ],
+ [ '\\\\', '' ],
+ [ 'a', 'a' ],
+ [ 'aaaa', 'aaaa' ],
+ [ '/a', 'a' ],
+ [ '\\a', 'a' ],
+ [ '/aaaa', 'aaaa' ],
+ [ '\\aaaa', 'aaaa' ],
+ [ '/aaaa/', 'aaaa' ],
+ [ '\\aaaa\\', 'aaaa' ],
+ [ '\\aaaa\\', 'aaaa' ],
+ [
+ '/mnt/upload3/wikipedia/en/thumb/8/8b/'
+ . 'Zork_Grand_Inquisitor_box_cover.jpg/93px-Zork_Grand_Inquisitor_box_cover.jpg',
+ '93px-Zork_Grand_Inquisitor_box_cover.jpg'
+ ],
+ [ 'C:\\Progra~1\\Wikime~1\\Wikipe~1\\VIEWER.EXE', 'VIEWER.EXE' ],
+ [ 'Östergötland_coat_of_arms.png', 'Östergötland_coat_of_arms.png' ],
+ ];
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php
new file mode 100644
index 00000000..7402054e
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfEscapeShellArg
+ */
+class WfEscapeShellArgTest extends MediaWikiTestCase {
+ public function testSingleInput() {
+ if ( wfIsWindows() ) {
+ $expected = '"blah"';
+ } else {
+ $expected = "'blah'";
+ }
+
+ $actual = wfEscapeShellArg( 'blah' );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function testMultipleArgs() {
+ if ( wfIsWindows() ) {
+ $expected = '"foo" "bar" "baz"';
+ } else {
+ $expected = "'foo' 'bar' 'baz'";
+ }
+
+ $actual = wfEscapeShellArg( 'foo', 'bar', 'baz' );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function testMultipleArgsAsArray() {
+ if ( wfIsWindows() ) {
+ $expected = '"foo" "bar" "baz"';
+ } else {
+ $expected = "'foo' 'bar' 'baz'";
+ }
+
+ $actual = wfEscapeShellArg( [ 'foo', 'bar', 'baz' ] );
+
+ $this->assertEquals( $expected, $actual );
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php
new file mode 100644
index 00000000..1cd320fa
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * @group GlobalFunctions
+ * @covers ::wfExpandUrl
+ */
+class WfExpandUrlTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideExpandableUrls
+ */
+ public function testWfExpandUrl( $fullUrl, $shortUrl, $defaultProto,
+ $server, $canServer, $httpsMode, $message
+ ) {
+ // Fake $wgServer, $wgCanonicalServer and $wgRequest->getProtocol()
+ $this->setMwGlobals( [
+ 'wgServer' => $server,
+ 'wgCanonicalServer' => $canServer,
+ 'wgRequest' => new FauxRequest( [], false, null, $httpsMode ? 'https' : 'http' )
+ ] );
+
+ $this->assertEquals( $fullUrl, wfExpandUrl( $shortUrl, $defaultProto ), $message );
+ }
+
+ /**
+ * Provider of URL examples for testing wfExpandUrl()
+ *
+ * @return array
+ */
+ public static function provideExpandableUrls() {
+ $modes = [ 'http', 'https' ];
+ $servers = [
+ 'http' => 'http://example.com',
+ 'https' => 'https://example.com',
+ 'protocol-relative' => '//example.com'
+ ];
+ $defaultProtos = [
+ 'http' => PROTO_HTTP,
+ 'https' => PROTO_HTTPS,
+ 'protocol-relative' => PROTO_RELATIVE,
+ 'current' => PROTO_CURRENT,
+ 'canonical' => PROTO_CANONICAL
+ ];
+
+ $retval = [];
+ foreach ( $modes as $mode ) {
+ $httpsMode = $mode == 'https';
+ foreach ( $servers as $serverDesc => $server ) {
+ foreach ( $modes as $canServerMode ) {
+ $canServer = "$canServerMode://example2.com";
+ foreach ( $defaultProtos as $protoDesc => $defaultProto ) {
+ $retval[] = [
+ 'http://example.com', 'http://example.com',
+ $defaultProto, $server, $canServer, $httpsMode,
+ "Testing fully qualified http URLs (no need to expand) "
+ . "(defaultProto: $protoDesc , wgServer: $server, "
+ . "wgCanonicalServer: $canServer, current request protocol: $mode )"
+ ];
+ $retval[] = [
+ 'https://example.com', 'https://example.com',
+ $defaultProto, $server, $canServer, $httpsMode,
+ "Testing fully qualified https URLs (no need to expand) "
+ . "(defaultProto: $protoDesc , wgServer: $server, "
+ . "wgCanonicalServer: $canServer, current request protocol: $mode )"
+ ];
+ # Would be nice to support this, see fixme on wfExpandUrl()
+ $retval[] = [
+ "wiki/FooBar", 'wiki/FooBar',
+ $defaultProto, $server, $canServer, $httpsMode,
+ "Test non-expandable relative URLs (defaultProto: $protoDesc, "
+ . "wgServer: $server, wgCanonicalServer: $canServer, "
+ . "current request protocol: $mode )"
+ ];
+
+ // Determine expected protocol
+ if ( $protoDesc == 'protocol-relative' ) {
+ $p = '';
+ } elseif ( $protoDesc == 'current' ) {
+ $p = "$mode:";
+ } elseif ( $protoDesc == 'canonical' ) {
+ $p = "$canServerMode:";
+ } else {
+ $p = $protoDesc . ':';
+ }
+ // Determine expected server name
+ if ( $protoDesc == 'canonical' ) {
+ $srv = $canServer;
+ } elseif ( $serverDesc == 'protocol-relative' ) {
+ $srv = $p . $server;
+ } else {
+ $srv = $server;
+ }
+
+ $retval[] = [
+ "$p//wikipedia.org", '//wikipedia.org',
+ $defaultProto, $server, $canServer, $httpsMode,
+ "Test protocol-relative URL (defaultProto: $protoDesc, "
+ . "wgServer: $server, wgCanonicalServer: $canServer, "
+ . "current request protocol: $mode )"
+ ];
+ $retval[] = [
+ "$srv/wiki/FooBar",
+ '/wiki/FooBar',
+ $defaultProto,
+ $server,
+ $canServer,
+ $httpsMode,
+ "Testing expanding URL beginning with / (defaultProto: $protoDesc, "
+ . "wgServer: $server, wgCanonicalServer: $canServer, "
+ . "current request protocol: $mode )"
+ ];
+ }
+ }
+ }
+ }
+
+ return $retval;
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfGetCallerTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfGetCallerTest.php
new file mode 100644
index 00000000..8a7bfa5a
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfGetCallerTest.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfGetCaller
+ */
+class WfGetCallerTest extends MediaWikiTestCase {
+ public function testZero() {
+ $this->assertEquals( 'WfGetCallerTest->testZero', wfGetCaller( 1 ) );
+ }
+
+ function callerOne() {
+ return wfGetCaller();
+ }
+
+ public function testOne() {
+ $this->assertEquals( 'WfGetCallerTest->testOne', self::callerOne() );
+ }
+
+ static function intermediateFunction( $level = 2, $n = 0 ) {
+ if ( $n > 0 ) {
+ return self::intermediateFunction( $level, $n - 1 );
+ }
+
+ return wfGetCaller( $level );
+ }
+
+ public function testTwo() {
+ $this->assertEquals( 'WfGetCallerTest->testTwo', self::intermediateFunction() );
+ }
+
+ public function testN() {
+ $this->assertEquals( 'WfGetCallerTest->testN', self::intermediateFunction( 2, 0 ) );
+ $this->assertEquals(
+ 'WfGetCallerTest::intermediateFunction',
+ self::intermediateFunction( 1, 0 )
+ );
+
+ for ( $i = 0; $i < 10; $i++ ) {
+ $this->assertEquals(
+ 'WfGetCallerTest::intermediateFunction',
+ self::intermediateFunction( $i + 1, $i )
+ );
+ }
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfParseUrlTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfParseUrlTest.php
new file mode 100644
index 00000000..b20cfb5c
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfParseUrlTest.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ * Copyright © 2013 Alexandre Emsenhuber
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfParseUrl
+ */
+class WfParseUrlTest extends MediaWikiTestCase {
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( 'wgUrlProtocols', [
+ '//',
+ 'http://',
+ 'https://',
+ 'file://',
+ 'mailto:',
+ ] );
+ }
+
+ /**
+ * @dataProvider provideURLs
+ */
+ public function testWfParseUrl( $url, $parts ) {
+ $this->assertEquals(
+ $parts,
+ wfParseUrl( $url )
+ );
+ }
+
+ /**
+ * Provider of URLs for testing wfParseUrl()
+ *
+ * @return array
+ */
+ public static function provideURLs() {
+ return [
+ [
+ '//example.org',
+ [
+ 'scheme' => '',
+ 'delimiter' => '//',
+ 'host' => 'example.org',
+ ]
+ ],
+ [
+ 'http://example.org',
+ [
+ 'scheme' => 'http',
+ 'delimiter' => '://',
+ 'host' => 'example.org',
+ ]
+ ],
+ [
+ 'https://example.org',
+ [
+ 'scheme' => 'https',
+ 'delimiter' => '://',
+ 'host' => 'example.org',
+ ]
+ ],
+ [
+ 'http://id:key@example.org:123/path?foo=bar#baz',
+ [
+ 'scheme' => 'http',
+ 'delimiter' => '://',
+ 'user' => 'id',
+ 'pass' => 'key',
+ 'host' => 'example.org',
+ 'port' => 123,
+ 'path' => '/path',
+ 'query' => 'foo=bar',
+ 'fragment' => 'baz',
+ ]
+ ],
+ [
+ 'file://example.org/etc/php.ini',
+ [
+ 'scheme' => 'file',
+ 'delimiter' => '://',
+ 'host' => 'example.org',
+ 'path' => '/etc/php.ini',
+ ]
+ ],
+ [
+ 'file:///etc/php.ini',
+ [
+ 'scheme' => 'file',
+ 'delimiter' => '://',
+ 'host' => '',
+ 'path' => '/etc/php.ini',
+ ]
+ ],
+ [
+ 'file:///c:/',
+ [
+ 'scheme' => 'file',
+ 'delimiter' => '://',
+ 'host' => '',
+ 'path' => '/c:/',
+ ]
+ ],
+ [
+ 'mailto:id@example.org',
+ [
+ 'scheme' => 'mailto',
+ 'delimiter' => ':',
+ 'host' => 'id@example.org',
+ 'path' => '',
+ ]
+ ],
+ [
+ 'mailto:id@example.org?subject=Foo',
+ [
+ 'scheme' => 'mailto',
+ 'delimiter' => ':',
+ 'host' => 'id@example.org',
+ 'path' => '',
+ 'query' => 'subject=Foo',
+ ]
+ ],
+ [
+ 'mailto:?subject=Foo',
+ [
+ 'scheme' => 'mailto',
+ 'delimiter' => ':',
+ 'host' => '',
+ 'path' => '',
+ 'query' => 'subject=Foo',
+ ]
+ ],
+ [
+ 'invalid://test/',
+ false
+ ],
+ ];
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php
new file mode 100644
index 00000000..eae5588b
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfRemoveDotSegments
+ */
+class WfRemoveDotSegmentsTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider providePaths
+ */
+ public function testWfRemoveDotSegments( $inputPath, $outputPath ) {
+ $this->assertEquals(
+ $outputPath,
+ wfRemoveDotSegments( $inputPath ),
+ "Testing $inputPath expands to $outputPath"
+ );
+ }
+
+ /**
+ * Provider of URL paths for testing wfRemoveDotSegments()
+ *
+ * @return array
+ */
+ public static function providePaths() {
+ return [
+ [ '/a/b/c/./../../g', '/a/g' ],
+ [ 'mid/content=5/../6', 'mid/6' ],
+ [ '/a//../b', '/a/b' ],
+ [ '/.../a', '/.../a' ],
+ [ '.../a', '.../a' ],
+ [ '', '' ],
+ [ '/', '/' ],
+ [ '//', '//' ],
+ [ '.', '' ],
+ [ '..', '' ],
+ [ '...', '...' ],
+ [ '/.', '/' ],
+ [ '/..', '/' ],
+ [ './', '' ],
+ [ '../', '' ],
+ [ './a', 'a' ],
+ [ '../a', 'a' ],
+ [ '../../a', 'a' ],
+ [ '.././a', 'a' ],
+ [ './../a', 'a' ],
+ [ '././a', 'a' ],
+ [ '../../', '' ],
+ [ '.././', '' ],
+ [ './../', '' ],
+ [ '././', '' ],
+ [ '../..', '' ],
+ [ '../.', '' ],
+ [ './..', '' ],
+ [ './.', '' ],
+ [ '/../../a', '/a' ],
+ [ '/.././a', '/a' ],
+ [ '/./../a', '/a' ],
+ [ '/././a', '/a' ],
+ [ '/../../', '/' ],
+ [ '/.././', '/' ],
+ [ '/./../', '/' ],
+ [ '/././', '/' ],
+ [ '/../..', '/' ],
+ [ '/../.', '/' ],
+ [ '/./..', '/' ],
+ [ '/./.', '/' ],
+ [ 'b/../../a', '/a' ],
+ [ 'b/.././a', '/a' ],
+ [ 'b/./../a', '/a' ],
+ [ 'b/././a', 'b/a' ],
+ [ 'b/../../', '/' ],
+ [ 'b/.././', '/' ],
+ [ 'b/./../', '/' ],
+ [ 'b/././', 'b/' ],
+ [ 'b/../..', '/' ],
+ [ 'b/../.', '/' ],
+ [ 'b/./..', '/' ],
+ [ 'b/./.', 'b/' ],
+ [ '/b/../../a', '/a' ],
+ [ '/b/.././a', '/a' ],
+ [ '/b/./../a', '/a' ],
+ [ '/b/././a', '/b/a' ],
+ [ '/b/../../', '/' ],
+ [ '/b/.././', '/' ],
+ [ '/b/./../', '/' ],
+ [ '/b/././', '/b/' ],
+ [ '/b/../..', '/' ],
+ [ '/b/../.', '/' ],
+ [ '/b/./..', '/' ],
+ [ '/b/./.', '/b/' ],
+ ];
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfShellExecTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfShellExecTest.php
new file mode 100644
index 00000000..fcd26f54
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfShellExecTest.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfShellExec
+ */
+class WfShellExecTest extends MediaWikiTestCase {
+ public function testBug67870() {
+ $command = wfIsWindows()
+ // 333 = 331 + CRLF
+ ? ( 'for /l %i in (1, 1, 1001) do @echo ' . str_repeat( '*', 331 ) )
+ : 'printf "%-333333s" "*"';
+
+ // Test several times because it involves a race condition that may randomly succeed or fail
+ for ( $i = 0; $i < 10; $i++ ) {
+ $output = wfShellExec( $command );
+ $this->assertEquals( 333333, strlen( $output ) );
+ }
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php
new file mode 100644
index 00000000..40b2e636
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfShorthandToInteger
+ */
+class WfShorthandToIntegerTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideABunchOfShorthands
+ */
+ public function testWfShorthandToInteger( $input, $output, $description ) {
+ $this->assertEquals(
+ wfShorthandToInteger( $input ),
+ $output,
+ $description
+ );
+ }
+
+ public static function provideABunchOfShorthands() {
+ return [
+ [ '', -1, 'Empty string' ],
+ [ ' ', -1, 'String of spaces' ],
+ [ '1G', 1024 * 1024 * 1024, 'One gig uppercased' ],
+ [ '1g', 1024 * 1024 * 1024, 'One gig lowercased' ],
+ [ '1M', 1024 * 1024, 'One meg uppercased' ],
+ [ '1m', 1024 * 1024, 'One meg lowercased' ],
+ [ '1K', 1024, 'One kb uppercased' ],
+ [ '1k', 1024, 'One kb lowercased' ],
+ ];
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfStringToBoolTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfStringToBoolTest.php
new file mode 100644
index 00000000..7f56b605
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfStringToBoolTest.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfStringToBool
+ */
+class WfStringToBoolTest extends MediaWikiTestCase {
+
+ public function getTestCases() {
+ return [
+ [ 'true', true ],
+ [ 'on', true ],
+ [ 'yes', true ],
+ [ 'TRUE', true ],
+ [ 'YeS', true ],
+ [ 'On', true ],
+ [ '1', true ],
+ [ '+1', true ],
+ [ '01', true ],
+ [ '-001', true ],
+ [ ' 1', true ],
+ [ '-1 ', true ],
+ [ '', false ],
+ [ '0', false ],
+ [ 'false', false ],
+ [ 'NO', false ],
+ [ 'NOT', false ],
+ [ 'never', false ],
+ [ '!&', false ],
+ [ '-0', false ],
+ [ '+0', false ],
+ [ 'forget about it', false ],
+ [ ' on', false ],
+ [ 'true ', false ],
+ ];
+ }
+
+ /**
+ * @dataProvider getTestCases
+ * @param string $str
+ * @param bool $bool
+ */
+ public function testStr2Bool( $str, $bool ) {
+ if ( $bool ) {
+ $this->assertTrue( wfStringToBool( $str ) );
+ } else {
+ $this->assertFalse( wfStringToBool( $str ) );
+ }
+ }
+
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php
new file mode 100644
index 00000000..bdba6a35
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php
@@ -0,0 +1,105 @@
+<?php
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfThumbIsStandard
+ */
+class WfThumbIsStandardTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( [
+ 'wgThumbLimits' => [
+ 100,
+ 401
+ ],
+ 'wgImageLimits' => [
+ [ 300, 225 ],
+ [ 800, 600 ],
+ ],
+ ] );
+ }
+
+ public static function provideThumbParams() {
+ return [
+ // Thumb limits
+ [
+ 'Standard thumb width',
+ true,
+ [ 'width' => 100 ],
+ ],
+ [
+ 'Standard thumb width',
+ true,
+ [ 'width' => 401 ],
+ ],
+ // wfThumbIsStandard should match Linker::processResponsiveImages
+ // in its rounding behaviour.
+ [
+ 'Standard thumb width (HiDPI 1.5x) - incorrect rounding',
+ false,
+ [ 'width' => 601 ],
+ ],
+ [
+ 'Standard thumb width (HiDPI 1.5x)',
+ true,
+ [ 'width' => 602 ],
+ ],
+ [
+ 'Standard thumb width (HiDPI 2x)',
+ true,
+ [ 'width' => 802 ],
+ ],
+ [
+ 'Non-standard thumb width',
+ false,
+ [ 'width' => 300 ],
+ ],
+ // Image limits
+ // Note: Image limits are measured as pairs. Individual values
+ // may be non-standard based on the aspect ratio.
+ [
+ 'Standard image width/height pair',
+ true,
+ [ 'width' => 250, 'height' => 225 ],
+ ],
+ [
+ 'Standard image width/height pair',
+ true,
+ [ 'width' => 667, 'height' => 600 ],
+ ],
+ [
+ 'Standard image width where image does not fit aspect ratio',
+ false,
+ [ 'width' => 300 ],
+ ],
+ [
+ 'Implicit width from image width/height pair aspect ratio fit',
+ true,
+ // 2000x1800 fit inside 300x225 makes w=250
+ [ 'width' => 250 ],
+ ],
+ [
+ 'Height-only is always non-standard',
+ false,
+ [ 'height' => 225 ],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideThumbParams
+ */
+ public function testIsStandard( $message, $expected, $params ) {
+ $handlers = MediaWikiServices::getInstance()->getMainConfig()->get( 'ParserTestMediaHandlers' );
+ $this->setService( 'MediaHandlerFactory', new MediaHandlerFactory( $handlers ) );
+ $this->assertSame(
+ $expected,
+ wfThumbIsStandard( new FakeDimensionFile( [ 2000, 1800 ], 'image/jpeg' ), $params ),
+ $message
+ );
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
new file mode 100644
index 00000000..a70f136a
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
@@ -0,0 +1,194 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfTimestamp
+ */
+class WfTimestampTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideNormalTimestamps
+ */
+ public function testNormalTimestamps( $input, $format, $output, $desc ) {
+ $this->assertEquals( $output, wfTimestamp( $format, $input ), $desc );
+ }
+
+ public static function provideNormalTimestamps() {
+ $t = gmmktime( 12, 34, 56, 1, 15, 2001 );
+
+ return [
+ // TS_UNIX
+ [ $t, TS_MW, '20010115123456', 'TS_UNIX to TS_MW' ],
+ [ -30281104, TS_MW, '19690115123456', 'Negative TS_UNIX to TS_MW' ],
+ [ $t, TS_UNIX, 979562096, 'TS_UNIX to TS_UNIX' ],
+ [ $t, TS_DB, '2001-01-15 12:34:56', 'TS_UNIX to TS_DB' ],
+ [ $t + 0.01, TS_MW, '20010115123456', 'TS_UNIX float to TS_MW' ],
+
+ [ $t, TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_ISO_8601_BASIC to TS_DB' ],
+
+ // TS_MW
+ [ '20010115123456', TS_MW, '20010115123456', 'TS_MW to TS_MW' ],
+ [ '20010115123456', TS_UNIX, 979562096, 'TS_MW to TS_UNIX' ],
+ [ '20010115123456', TS_DB, '2001-01-15 12:34:56', 'TS_MW to TS_DB' ],
+ [ '20010115123456', TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_MW to TS_ISO_8601_BASIC' ],
+
+ // TS_DB
+ [ '2001-01-15 12:34:56', TS_MW, '20010115123456', 'TS_DB to TS_MW' ],
+ [ '2001-01-15 12:34:56', TS_UNIX, 979562096, 'TS_DB to TS_UNIX' ],
+ [ '2001-01-15 12:34:56', TS_DB, '2001-01-15 12:34:56', 'TS_DB to TS_DB' ],
+ [
+ '2001-01-15 12:34:56',
+ TS_ISO_8601_BASIC,
+ '20010115T123456Z',
+ 'TS_DB to TS_ISO_8601_BASIC'
+ ],
+
+ # rfc2822 section 3.3
+ [ '20010115123456', TS_RFC2822, 'Mon, 15 Jan 2001 12:34:56 GMT', 'TS_MW to TS_RFC2822' ],
+ [ 'Mon, 15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 to TS_MW' ],
+ [
+ ' Mon, 15 Jan 2001 12:34:56 GMT',
+ TS_MW,
+ '20010115123456',
+ 'TS_RFC2822 with leading space to TS_MW'
+ ],
+ [
+ '15 Jan 2001 12:34:56 GMT',
+ TS_MW,
+ '20010115123456',
+ 'TS_RFC2822 without optional day-of-week to TS_MW'
+ ],
+
+ # FWS = ([*WSP CRLF] 1*WSP) / obs-FWS ; Folding white space
+ # obs-FWS = 1*WSP *(CRLF 1*WSP) ; Section 4.2
+ [ 'Mon, 15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 to TS_MW' ],
+
+ # WSP = SP / HTAB ; rfc2234
+ [
+ "Mon, 15 Jan\x092001 12:34:56 GMT",
+ TS_MW,
+ '20010115123456',
+ 'TS_RFC2822 with HTAB to TS_MW'
+ ],
+ [
+ "Mon, 15 Jan\x09 \x09 2001 12:34:56 GMT",
+ TS_MW,
+ '20010115123456',
+ 'TS_RFC2822 with HTAB and SP to TS_MW'
+ ],
+ [
+ 'Sun, 6 Nov 94 08:49:37 GMT',
+ TS_MW,
+ '19941106084937',
+ 'TS_RFC2822 with obsolete year to TS_MW'
+ ],
+ ];
+ }
+
+ /**
+ * This test checks wfTimestamp() with values outside.
+ * It needs PHP 64 bits or PHP > 5.1.
+ * See r74778 and T27451
+ * @dataProvider provideOldTimestamps
+ */
+ public function testOldTimestamps( $input, $outputType, $output, $message ) {
+ $timestamp = wfTimestamp( $outputType, $input );
+ if ( substr( $output, 0, 1 ) === '/' ) {
+ // T66946: Day of the week calculations for very old
+ // timestamps varies from system to system.
+ $this->assertRegExp( $output, $timestamp, $message );
+ } else {
+ $this->assertEquals( $output, $timestamp, $message );
+ }
+ }
+
+ public static function provideOldTimestamps() {
+ return [
+ [
+ '19011213204554',
+ TS_RFC2822,
+ 'Fri, 13 Dec 1901 20:45:54 GMT',
+ 'Earliest time according to PHP documentation'
+ ],
+ [ '20380119031407', TS_RFC2822, 'Tue, 19 Jan 2038 03:14:07 GMT', 'Latest 32 bit time' ],
+ [ '19011213204552', TS_UNIX, '-2147483648', 'Earliest 32 bit unix time' ],
+ [ '20380119031407', TS_UNIX, '2147483647', 'Latest 32 bit unix time' ],
+ [ '19011213204552', TS_RFC2822, 'Fri, 13 Dec 1901 20:45:52 GMT', 'Earliest 32 bit time' ],
+ [
+ '19011213204551',
+ TS_RFC2822,
+ 'Fri, 13 Dec 1901 20:45:51 GMT', 'Earliest 32 bit time - 1'
+ ],
+ [ '20380119031408', TS_RFC2822, 'Tue, 19 Jan 2038 03:14:08 GMT', 'Latest 32 bit time + 1' ],
+ [ '19011212000000', TS_MW, '19011212000000', 'Convert to itself r74778#c10645' ],
+ [ '19011213204551', TS_UNIX, '-2147483649', 'Earliest 32 bit unix time - 1' ],
+ [ '20380119031408', TS_UNIX, '2147483648', 'Latest 32 bit unix time + 1' ],
+ [ '-2147483649', TS_MW, '19011213204551', '1901 negative unix time to MediaWiki' ],
+ [ '-5331871504', TS_MW, '18010115123456', '1801 negative unix time to MediaWiki' ],
+ [
+ '0117-08-09 12:34:56',
+ TS_RFC2822,
+ '/, 09 Aug 0117 12:34:56 GMT$/',
+ 'Death of Roman Emperor [[Trajan]]'
+ ],
+
+ /* @todo FIXME: 00 to 101 years are taken as being in [1970-2069] */
+ [ '-58979923200', TS_RFC2822, '/, 01 Jan 0101 00:00:00 GMT$/', '1/1/101' ],
+ [ '-62135596800', TS_RFC2822, 'Mon, 01 Jan 0001 00:00:00 GMT', 'Year 1' ],
+
+ /* It is not clear if we should generate a year 0 or not
+ * We are completely off RFC2822 requirement of year being
+ * 1900 or later.
+ */
+ [
+ '-62142076800',
+ TS_RFC2822,
+ 'Wed, 18 Oct 0000 00:00:00 GMT',
+ 'ISO 8601:2004 [[year 0]], also called [[1 BC]]'
+ ],
+ ];
+ }
+
+ /**
+ * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
+ * @dataProvider provideHttpDates
+ */
+ public function testHttpDate( $input, $output, $desc ) {
+ $this->assertEquals( $output, wfTimestamp( TS_MW, $input ), $desc );
+ }
+
+ public static function provideHttpDates() {
+ return [
+ [ 'Sun, 06 Nov 1994 08:49:37 GMT', '19941106084937', 'RFC 822 date' ],
+ [ 'Sunday, 06-Nov-94 08:49:37 GMT', '19941106084937', 'RFC 850 date' ],
+ [ 'Sun Nov 6 08:49:37 1994', '19941106084937', "ANSI C's asctime() format" ],
+ // See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html and r77171
+ [
+ 'Mon, 22 Nov 2010 14:12:42 GMT; length=52626',
+ '20101122141242',
+ 'Netscape extension to HTTP/1.0'
+ ],
+ ];
+ }
+
+ /**
+ * 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
+ */
+ public function testTimestampParameter() {
+ $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 );
+ }
+}
diff --git a/www/wiki/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
new file mode 100644
index 00000000..09c1040b
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * The function only need a string parameter and might react to IIS7.0
+ *
+ * @group GlobalFunctions
+ * @covers ::wfUrlencode
+ */
+class WfUrlencodeTest extends MediaWikiTestCase {
+ # ### TESTS ##############################################################
+
+ /**
+ * @dataProvider provideURLS
+ */
+ public function testEncodingUrlWith( $input, $expected ) {
+ $this->verifyEncodingFor( 'Apache', $input, $expected );
+ }
+
+ /**
+ * @dataProvider provideURLS
+ */
+ public function testEncodingUrlWithMicrosoftIis7( $input, $expected ) {
+ $this->verifyEncodingFor( 'Microsoft-IIS/7', $input, $expected );
+ }
+
+ # ### HELPERS #############################################################
+
+ /**
+ * Internal helper that actually run the test.
+ * Called by the public methods testEncodingUrlWith...()
+ */
+ private function verifyEncodingFor( $server, $input, $expectations ) {
+ $expected = $this->extractExpect( $server, $expectations );
+
+ // save up global
+ $old = isset( $_SERVER['SERVER_SOFTWARE'] )
+ ? $_SERVER['SERVER_SOFTWARE']
+ : null;
+ $_SERVER['SERVER_SOFTWARE'] = $server;
+ wfUrlencode( null );
+
+ // do the requested test
+ $this->assertEquals(
+ $expected,
+ wfUrlencode( $input ),
+ "Encoding '$input' for server '$server' should be '$expected'"
+ );
+
+ // restore global
+ if ( $old === null ) {
+ unset( $_SERVER['SERVER_SOFTWARE'] );
+ } else {
+ $_SERVER['SERVER_SOFTWARE'] = $old;
+ }
+ wfUrlencode( null );
+ }
+
+ /**
+ * Interprets the provider array. Return expected value depending
+ * the HTTP server name.
+ */
+ private function extractExpect( $server, $expectations ) {
+ if ( is_string( $expectations ) ) {
+ return $expectations;
+ } elseif ( is_array( $expectations ) ) {
+ if ( !array_key_exists( $server, $expectations ) ) {
+ throw new MWException( __METHOD__ . " expectation does not have any "
+ . "value for server name $server. Check the provider array.\n" );
+ } else {
+ return $expectations[$server];
+ }
+ } else {
+ throw new MWException( __METHOD__ . " given invalid expectation for "
+ . "'$server'. Should be a string or an array( <http server name> => <string> ).\n" );
+ }
+ }
+
+ # ### PROVIDERS ###########################################################
+
+ /**
+ * Format is either:
+ * [ 'input', 'expected' ];
+ * Or:
+ * [ 'input',
+ * [ 'Apache', 'expected' ],
+ * [ 'Microsoft-IIS/7', 'expected' ],
+ * ],
+ * If you want to add other HTTP server name, you will have to add a new
+ * testing method much like the testEncodingUrlWith() method above.
+ */
+ public static function provideURLS() {
+ return [
+ # ## RFC 1738 chars
+ // + is not safe
+ [ '+', '%2B' ],
+ // & and = not safe in queries
+ [ '&', '%26' ],
+ [ '=', '%3D' ],
+
+ [ ':', [
+ 'Apache' => ':',
+ 'Microsoft-IIS/7' => '%3A',
+ ] ],
+
+ // remaining chars do not need encoding
+ [
+ ';@$-_.!*',
+ ';@$-_.!*',
+ ],
+
+ # ## Other tests
+ // slash remain unchanged. %2F seems to break things
+ [ '/', '/' ],
+ // T105265
+ [ '~', '~' ],
+
+ // Other 'funnies' chars
+ [ '[]', '%5B%5D' ],
+ [ '<>', '%3C%3E' ],
+
+ // Apostrophe is encoded
+ [ '\'', '%27' ],
+ ];
+ }
+}