global $wgSessionProviders, $wgSessionPbkdf2Iterations;
global $wgJobTypeConf;
global $wgAuthManagerConfig;
+ global $wgShowExceptionDetails;
+
+ $wgShowExceptionDetails = true;
// wfWarn should cause tests to fail
$wgDevelopmentWarnings = true;
'HamcrestPHPUnitIntegration' => "$testDir/phpunit/HamcrestPHPUnitIntegration.php",
'LessFileCompilationTest' => "$testDir/phpunit/LessFileCompilationTest.php",
'MediaWikiCoversValidator' => "$testDir/phpunit/MediaWikiCoversValidator.php",
+ 'MediaWikiGroupValidator' => "$testDir/phpunit/MediaWikiGroupValidator.php",
'MediaWikiLangTestCase' => "$testDir/phpunit/MediaWikiLangTestCase.php",
'MediaWikiLoggerPHPUnitTestListener' => "$testDir/phpunit/MediaWikiLoggerPHPUnitTestListener.php",
'MediaWikiPHPUnitCommand' => "$testDir/phpunit/MediaWikiPHPUnitCommand.php",
--- /dev/null
+<?php
+/**
+ * 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
+ * @ingroup Testing
+ */
+
+/**
+ * Trait that provides methods to check if group annotations are valid.
+ */
+trait MediaWikiGroupValidator {
+
+ /**
+ * @return bool
+ * @throws ReflectionException
+ * @since 1.34
+ */
+ public function isTestInDatabaseGroup() {
+ // If the test class says it belongs to the Database group, it needs the database.
+ // NOTE: This ONLY checks for the group in the class level doc comment.
+ $rc = new ReflectionClass( $this );
+ return (bool)preg_match( '/@group +Database/im', $rc->getDocComment() );
+ }
+}
use MediaWikiCoversValidator;
use PHPUnit4And6Compat;
+ use MediaWikiGroupValidator;
/**
* The original service locator. This is overridden during setUp().
return $this->tablesUsed || $this->isTestInDatabaseGroup();
}
- /**
- * @return bool
- * @since 1.32
- */
- protected function isTestInDatabaseGroup() {
- // If the test class says it belongs to the Database group, it needs the database.
- // NOTE: This ONLY checks for the group in the class level doc comment.
- $rc = new ReflectionClass( $this );
- return (bool)preg_match( '/@group +Database/im', $rc->getDocComment() );
- }
-
/**
* Insert a new page.
*
abstract class MediaWikiUnitTestCase extends TestCase {
use PHPUnit4And6Compat;
use MediaWikiCoversValidator;
+ use MediaWikiGroupValidator;
+
+ /**
+ * @throws ReflectionException
+ */
+ protected function setUp() {
+ parent::setUp();
+ if ( $this->isTestInDatabaseGroup() ) {
+ throw new \Exception( get_class( $this ) .
+ ' extends MediaWikiUnitTestCase, and may not have the @group Database annotation.' );
+ }
+ }
+
}
wfRequireOnceInGlobalScope( "$IP/includes/AutoLoader.php" );
wfRequireOnceInGlobalScope( "$IP/tests/common/TestsAutoLoader.php" );
+wfRequireOnceInGlobalScope( "$IP/includes/Defines.php" );
+++ /dev/null
-<?php
-/**
- * Copyright @ 2011 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
- */
-
-class FauxResponseTest extends MediaWikiTestCase {
- /** @var FauxResponse */
- protected $response;
-
- protected function setUp() {
- parent::setUp();
- $this->response = new FauxResponse;
- }
-
- /**
- * @covers FauxResponse::setCookie
- * @covers FauxResponse::getCookie
- * @covers FauxResponse::getCookieData
- * @covers FauxResponse::getCookies
- */
- public function testCookie() {
- $expire = time() + 100;
- $cookie = [
- 'value' => 'val',
- 'path' => '/path',
- 'domain' => 'domain',
- 'secure' => true,
- 'httpOnly' => false,
- 'raw' => false,
- 'expire' => $expire,
- ];
-
- $this->assertEquals( null, $this->response->getCookie( 'xkey' ), 'Non-existing cookie' );
- $this->response->setCookie( 'key', 'val', $expire, [
- 'prefix' => 'x',
- 'path' => '/path',
- 'domain' => 'domain',
- 'secure' => 1,
- 'httpOnly' => 0,
- ] );
- $this->assertEquals( 'val', $this->response->getCookie( 'xkey' ), 'Existing cookie' );
- $this->assertEquals( $cookie, $this->response->getCookieData( 'xkey' ),
- 'Existing cookie (data)' );
- $this->assertEquals( [ 'xkey' => $cookie ], $this->response->getCookies(),
- 'Existing cookies' );
- }
-
- /**
- * @covers FauxResponse::getheader
- * @covers FauxResponse::header
- */
- public function testHeader() {
- $this->assertEquals( null, $this->response->getHeader( 'Location' ), 'Non-existing header' );
-
- $this->response->header( 'Location: http://localhost/' );
- $this->assertEquals(
- 'http://localhost/',
- $this->response->getHeader( 'Location' ),
- 'Set header'
- );
-
- $this->response->header( 'Location: http://127.0.0.1/' );
- $this->assertEquals(
- 'http://127.0.0.1/',
- $this->response->getHeader( 'Location' ),
- 'Same header'
- );
-
- $this->response->header( 'Location: http://127.0.0.2/', false );
- $this->assertEquals(
- 'http://127.0.0.1/',
- $this->response->getHeader( 'Location' ),
- 'Same header with override disabled'
- );
-
- $this->response->header( 'Location: http://localhost/' );
- $this->assertEquals(
- 'http://localhost/',
- $this->response->getHeader( 'LOCATION' ),
- 'Get header case insensitive'
- );
- }
-
- /**
- * @covers FauxResponse::getStatusCode
- */
- public function testResponseCode() {
- $this->response->header( 'HTTP/1.1 200' );
- $this->assertEquals( 200, $this->response->getStatusCode(), 'Header with no message' );
-
- $this->response->header( 'HTTP/1.x 201' );
- $this->assertEquals(
- 201,
- $this->response->getStatusCode(),
- 'Header with no message and protocol 1.x'
- );
-
- $this->response->header( 'HTTP/1.1 202 OK' );
- $this->assertEquals( 202, $this->response->getStatusCode(), 'Normal header' );
-
- $this->response->header( 'HTTP/1.x 203 OK' );
- $this->assertEquals(
- 203,
- $this->response->getStatusCode(),
- 'Normal header with no message and protocol 1.x'
- );
-
- $this->response->header( 'HTTP/1.x 204 OK', false, 205 );
- $this->assertEquals(
- 205,
- $this->response->getStatusCode(),
- 'Third parameter overrides the HTTP/... header'
- );
-
- $this->response->statusHeader( 210 );
- $this->assertEquals(
- 210,
- $this->response->getStatusCode(),
- 'Handle statusHeader method'
- );
-
- $this->response->header( 'Location: http://localhost/', false, 206 );
- $this->assertEquals(
- 206,
- $this->response->getStatusCode(),
- 'Third parameter with another header'
- );
- }
-}
+++ /dev/null
-<?php
-
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * Test class for FormOptions initialization
- * Ensure the FormOptions::add() does what we want it to do.
- *
- * Copyright © 2011, Antoine Musso
- *
- * @author Antoine Musso
- */
-class FormOptionsInitializationTest extends MediaWikiTestCase {
- /**
- * @var FormOptions
- */
- protected $object;
-
- /**
- * A new fresh and empty FormOptions object to test initialization
- * with.
- */
- protected function setUp() {
- parent::setUp();
- $this->object = TestingAccessWrapper::newFromObject( new FormOptions() );
- }
-
- /**
- * @covers FormOptions::add
- */
- public function testAddStringOption() {
- $this->object->add( 'foo', 'string value' );
- $this->assertEquals(
- [
- 'foo' => [
- 'default' => 'string value',
- 'consumed' => false,
- 'type' => FormOptions::STRING,
- 'value' => null,
- ]
- ],
- $this->object->options
- );
- }
-
- /**
- * @covers FormOptions::add
- */
- public function testAddIntegers() {
- $this->object->add( 'one', 1 );
- $this->object->add( 'negone', -1 );
- $this->assertEquals(
- [
- 'negone' => [
- 'default' => -1,
- 'value' => null,
- 'consumed' => false,
- 'type' => FormOptions::INT,
- ],
- 'one' => [
- 'default' => 1,
- 'value' => null,
- 'consumed' => false,
- 'type' => FormOptions::INT,
- ]
- ],
- $this->object->options
- );
- }
-}
+++ /dev/null
-<?php
-/**
- * This file host two test case classes for the MediaWiki FormOptions class:
- * - FormOptionsInitializationTest : tests initialization of the class.
- * - FormOptionsTest : tests methods an on instance
- *
- * The split let us take advantage of setting up a fixture for the methods
- * tests.
- */
-
-/**
- * Test class for FormOptions methods.
- *
- * Copyright © 2011, Antoine Musso
- *
- * @author Antoine Musso
- */
-class FormOptionsTest extends MediaWikiTestCase {
- /**
- * @var FormOptions
- */
- protected $object;
-
- /**
- * Instanciates a FormOptions object to play with.
- * FormOptions::add() is tested by the class FormOptionsInitializationTest
- * so we assume the function is well tested already an use it to create
- * the fixture.
- */
- protected function setUp() {
- parent::setUp();
- $this->object = new FormOptions;
- $this->object->add( 'string1', 'string one' );
- $this->object->add( 'string2', 'string two' );
- $this->object->add( 'integer', 0 );
- $this->object->add( 'float', 0.0 );
- $this->object->add( 'intnull', 0, FormOptions::INTNULL );
- }
-
- /** Helpers for testGuessType() */
- /* @{ */
- private function assertGuessBoolean( $data ) {
- $this->guess( FormOptions::BOOL, $data );
- }
-
- private function assertGuessInt( $data ) {
- $this->guess( FormOptions::INT, $data );
- }
-
- private function assertGuessFloat( $data ) {
- $this->guess( FormOptions::FLOAT, $data );
- }
-
- private function assertGuessString( $data ) {
- $this->guess( FormOptions::STRING, $data );
- }
-
- private function assertGuessArray( $data ) {
- $this->guess( FormOptions::ARR, $data );
- }
-
- /** Generic helper */
- private function guess( $expected, $data ) {
- $this->assertEquals(
- $expected,
- FormOptions::guessType( $data )
- );
- }
-
- /* @} */
-
- /**
- * Reuse helpers above assertGuessBoolean assertGuessInt assertGuessString
- * @covers FormOptions::guessType
- */
- public function testGuessTypeDetection() {
- $this->assertGuessBoolean( true );
- $this->assertGuessBoolean( false );
-
- $this->assertGuessInt( 0 );
- $this->assertGuessInt( -5 );
- $this->assertGuessInt( 5 );
- $this->assertGuessInt( 0x0F );
-
- $this->assertGuessFloat( 0.0 );
- $this->assertGuessFloat( 1.5 );
- $this->assertGuessFloat( 1e3 );
-
- $this->assertGuessString( 'true' );
- $this->assertGuessString( 'false' );
- $this->assertGuessString( '5' );
- $this->assertGuessString( '0' );
- $this->assertGuessString( '1.5' );
-
- $this->assertGuessArray( [ 'foo' ] );
- }
-
- /**
- * @expectedException MWException
- * @covers FormOptions::guessType
- */
- public function testGuessTypeOnNullThrowException() {
- $this->object->guessType( null );
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @covers Licenses
- */
-class LicensesTest extends MediaWikiTestCase {
-
- public function testLicenses() {
- $str = "
-* Free licenses:
-** GFDL|Debian disagrees
-";
-
- $lc = new Licenses( [
- 'fieldname' => 'FooField',
- 'type' => 'select',
- 'section' => 'description',
- 'id' => 'wpLicense',
- 'label' => 'A label text', # Note can't test label-message because $wgOut is not defined
- 'name' => 'AnotherName',
- 'licenses' => $str,
- ] );
- $this->assertThat( $lc, $this->isInstanceOf( Licenses::class ) );
- }
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Rest;
-
-use MediaWikiTestCase;
-use MediaWiki\Rest\HeaderContainer;
-
-/**
- * @covers \MediaWiki\Rest\HeaderContainer
- */
-class HeaderContainerTest extends MediaWikiTestCase {
- public static function provideSetHeader() {
- return [
- 'simple' => [
- [
- [ 'Test', 'foo' ]
- ],
- [ 'Test' => [ 'foo' ] ],
- [ 'Test' => 'foo' ]
- ],
- 'replace' => [
- [
- [ 'Test', 'foo' ],
- [ 'Test', 'bar' ],
- ],
- [ 'Test' => [ 'bar' ] ],
- [ 'Test' => 'bar' ],
- ],
- 'array value' => [
- [
- [ 'Test', [ '1', '2' ] ],
- [ 'Test', [ '3', '4' ] ],
- ],
- [ 'Test' => [ '3', '4' ] ],
- [ 'Test' => '3, 4' ]
- ],
- 'preserve most recent case' => [
- [
- [ 'test', 'foo' ],
- [ 'tesT', 'bar' ],
- ],
- [ 'tesT' => [ 'bar' ] ],
- [ 'tesT' => 'bar' ]
- ],
- 'empty' => [ [], [], [] ],
- ];
- }
-
- /** @dataProvider provideSetHeader */
- public function testSetHeader( $setOps, $headers, $lines ) {
- $hc = new HeaderContainer;
- foreach ( $setOps as list( $name, $value ) ) {
- $hc->setHeader( $name, $value );
- }
- $this->assertSame( $headers, $hc->getHeaders() );
- $this->assertSame( $lines, $hc->getHeaderLines() );
- }
-
- public static function provideAddHeader() {
- return [
- 'simple' => [
- [
- [ 'Test', 'foo' ]
- ],
- [ 'Test' => [ 'foo' ] ],
- [ 'Test' => 'foo' ]
- ],
- 'add' => [
- [
- [ 'Test', 'foo' ],
- [ 'Test', 'bar' ],
- ],
- [ 'Test' => [ 'foo', 'bar' ] ],
- [ 'Test' => 'foo, bar' ],
- ],
- 'array value' => [
- [
- [ 'Test', [ '1', '2' ] ],
- [ 'Test', [ '3', '4' ] ],
- ],
- [ 'Test' => [ '1', '2', '3', '4' ] ],
- [ 'Test' => '1, 2, 3, 4' ]
- ],
- 'preserve original case' => [
- [
- [ 'Test', 'foo' ],
- [ 'tesT', 'bar' ],
- ],
- [ 'Test' => [ 'foo', 'bar' ] ],
- [ 'Test' => 'foo, bar' ]
- ],
- ];
- }
-
- /** @dataProvider provideAddHeader */
- public function testAddHeader( $addOps, $headers, $lines ) {
- $hc = new HeaderContainer;
- foreach ( $addOps as list( $name, $value ) ) {
- $hc->addHeader( $name, $value );
- }
- $this->assertSame( $headers, $hc->getHeaders() );
- $this->assertSame( $lines, $hc->getHeaderLines() );
- }
-
- public static function provideRemoveHeader() {
- return [
- 'simple' => [
- [ [ 'Test', 'foo' ] ],
- [ 'Test' ],
- [],
- []
- ],
- 'case mismatch' => [
- [ [ 'Test', 'foo' ] ],
- [ 'tesT' ],
- [],
- []
- ],
- 'remove nonexistent' => [
- [ [ 'A', '1' ] ],
- [ 'B' ],
- [ 'A' => [ '1' ] ],
- [ 'A' => '1' ]
- ],
- ];
- }
-
- /** @dataProvider provideRemoveHeader */
- public function testRemoveHeader( $addOps, $removeOps, $headers, $lines ) {
- $hc = new HeaderContainer;
- foreach ( $addOps as list( $name, $value ) ) {
- $hc->addHeader( $name, $value );
- }
- foreach ( $removeOps as $name ) {
- $hc->removeHeader( $name );
- }
- $this->assertSame( $headers, $hc->getHeaders() );
- $this->assertSame( $lines, $hc->getHeaderLines() );
- }
-
- public function testHasHeader() {
- $hc = new HeaderContainer;
- $hc->addHeader( 'A', '1' );
- $hc->addHeader( 'B', '2' );
- $hc->addHeader( 'C', '3' );
- $hc->removeHeader( 'B' );
- $hc->removeHeader( 'c' );
- $this->assertTrue( $hc->hasHeader( 'A' ) );
- $this->assertTrue( $hc->hasHeader( 'a' ) );
- $this->assertFalse( $hc->hasHeader( 'B' ) );
- $this->assertFalse( $hc->hasHeader( 'c' ) );
- $this->assertFalse( $hc->hasHeader( 'C' ) );
- }
-
- public function testGetRawHeaderLines() {
- $hc = new HeaderContainer;
- $hc->addHeader( 'A', '1' );
- $hc->addHeader( 'a', '2' );
- $hc->addHeader( 'b', '3' );
- $hc->addHeader( 'Set-Cookie', 'x' );
- $hc->addHeader( 'SET-cookie', 'y' );
- $this->assertSame(
- [
- 'A: 1, 2',
- 'b: 3',
- 'Set-Cookie: x',
- 'Set-Cookie: y',
- ],
- $hc->getRawHeaderLines()
- );
- }
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Rest\PathTemplateMatcher;
-
-use MediaWiki\Rest\PathTemplateMatcher\PathConflict;
-use MediaWiki\Rest\PathTemplateMatcher\PathMatcher;
-use MediaWikiTestCase;
-
-/**
- * @covers \MediaWiki\Rest\PathTemplateMatcher\PathMatcher
- * @covers \MediaWiki\Rest\PathTemplateMatcher\PathConflict
- */
-class PathMatcherTest extends MediaWikiTestCase {
- private static $normalRoutes = [
- '/a/b',
- '/b/{x}',
- '/c/{x}/d',
- '/c/{x}/e',
- '/c/{x}/{y}/d',
- ];
-
- public static function provideConflictingRoutes() {
- return [
- [ '/a/b', 0, '/a/b' ],
- [ '/a/{x}', 0, '/a/b' ],
- [ '/{x}/c', 1, '/b/{x}' ],
- [ '/b/a', 1, '/b/{x}' ],
- [ '/b/{x}', 1, '/b/{x}' ],
- [ '/{x}/{y}/d', 2, '/c/{x}/d' ],
- ];
- }
-
- public static function provideMatch() {
- return [
- [ '', false ],
- [ '/a/b', [ 'params' => [], 'userData' => 0 ] ],
- [ '/b', false ],
- [ '/b/1', [ 'params' => [ 'x' => '1' ], 'userData' => 1 ] ],
- [ '/c/1/d', [ 'params' => [ 'x' => '1' ], 'userData' => 2 ] ],
- [ '/c/1/e', [ 'params' => [ 'x' => '1' ], 'userData' => 3 ] ],
- [ '/c/000/e', [ 'params' => [ 'x' => '000' ], 'userData' => 3 ] ],
- [ '/c/1/f', false ],
- [ '/c//e', [ 'params' => [ 'x' => '' ], 'userData' => 3 ] ],
- [ '/c///e', false ],
- ];
- }
-
- public function createNormalRouter() {
- $pm = new PathMatcher;
- foreach ( self::$normalRoutes as $i => $route ) {
- $pm->add( $route, $i );
- }
- return $pm;
- }
-
- /** @dataProvider provideConflictingRoutes */
- public function testAddConflict( $attempt, $expectedUserData, $expectedTemplate ) {
- $pm = $this->createNormalRouter();
- $actualTemplate = null;
- $actualUserData = null;
- try {
- $pm->add( $attempt, 'conflict' );
- } catch ( PathConflict $pc ) {
- $actualTemplate = $pc->existingTemplate;
- $actualUserData = $pc->existingUserData;
- }
- $this->assertSame( $expectedUserData, $actualUserData );
- $this->assertSame( $expectedTemplate, $actualTemplate );
- }
-
- /** @dataProvider provideMatch */
- public function testMatch( $path, $expectedResult ) {
- $pm = $this->createNormalRouter();
- $result = $pm->match( $path );
- $this->assertSame( $expectedResult, $result );
- }
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Rest;
-
-use MediaWiki\Rest\StringStream;
-use MediaWikiTestCase;
-
-/** @covers \MediaWiki\Rest\StringStream */
-class StringStreamTest extends MediaWikiTestCase {
- public static function provideSeekGetContents() {
- return [
- [ 'abcde', 0, SEEK_SET, 'abcde' ],
- [ 'abcde', 1, SEEK_SET, 'bcde' ],
- [ 'abcde', 5, SEEK_SET, '' ],
- [ 'abcde', 1, SEEK_CUR, 'cde' ],
- [ 'abcde', 0, SEEK_END, '' ],
- ];
- }
-
- /** @dataProvider provideSeekGetContents */
- public function testCopyToStream( $input, $offset, $whence, $expected ) {
- $ss = new StringStream;
- $ss->write( $input );
- $ss->seek( 1 );
- $ss->seek( $offset, $whence );
- $destStream = fopen( 'php://memory', 'w+' );
- $ss->copyToStream( $destStream );
- fseek( $destStream, 0 );
- $result = stream_get_contents( $destStream );
- $this->assertSame( $expected, $result );
- }
-
- public function testGetSize() {
- $ss = new StringStream;
- $this->assertSame( 0, $ss->getSize() );
- $ss->write( "hello" );
- $this->assertSame( 5, $ss->getSize() );
- $ss->rewind();
- $this->assertSame( 5, $ss->getSize() );
- }
-
- public function testTell() {
- $ss = new StringStream;
- $this->assertSame( $ss->tell(), 0 );
- $ss->write( "abc" );
- $this->assertSame( $ss->tell(), 3 );
- $ss->seek( 0 );
- $ss->read( 1 );
- $this->assertSame( $ss->tell(), 1 );
- }
-
- public function testEof() {
- $ss = new StringStream( 'abc' );
- $this->assertFalse( $ss->eof() );
- $ss->read( 1 );
- $this->assertFalse( $ss->eof() );
- $ss->read( 1 );
- $this->assertFalse( $ss->eof() );
- $ss->read( 1 );
- $this->assertTrue( $ss->eof() );
- $ss->rewind();
- $this->assertFalse( $ss->eof() );
- }
-
- public function testIsSeekable() {
- $ss = new StringStream;
- $this->assertTrue( $ss->isSeekable() );
- }
-
- public function testIsReadable() {
- $ss = new StringStream;
- $this->assertTrue( $ss->isReadable() );
- }
-
- public function testIsWritable() {
- $ss = new StringStream;
- $this->assertTrue( $ss->isWritable() );
- }
-
- public function testSeekWrite() {
- $ss = new StringStream;
- $this->assertSame( '', (string)$ss );
- $ss->write( 'a' );
- $this->assertSame( 'a', (string)$ss );
- $ss->write( 'b' );
- $this->assertSame( 'ab', (string)$ss );
- $ss->seek( 1 );
- $ss->write( 'c' );
- $this->assertSame( 'ac', (string)$ss );
- }
-
- /** @dataProvider provideSeekGetContents */
- public function testSeekGetContents( $input, $offset, $whence, $expected ) {
- $ss = new StringStream( $input );
- $ss->seek( 1 );
- $ss->seek( $offset, $whence );
- $this->assertSame( $expected, $ss->getContents() );
- }
-
- public static function provideSeekRead() {
- return [
- [ 'abcde', 0, SEEK_SET, 1, 'a' ],
- [ 'abcde', 0, SEEK_SET, 2, 'ab' ],
- [ 'abcde', 4, SEEK_SET, 2, 'e' ],
- [ 'abcde', 5, SEEK_SET, 1, '' ],
- [ 'abcde', 1, SEEK_CUR, 1, 'c' ],
- [ 'abcde', 0, SEEK_END, 1, '' ],
- [ 'abcde', -1, SEEK_END, 1, 'e' ],
- ];
- }
-
- /** @dataProvider provideSeekRead */
- public function testSeekRead( $input, $offset, $whence, $length, $expected ) {
- $ss = new StringStream( $input );
- $ss->seek( 1 );
- $ss->seek( $offset, $whence );
- $this->assertSame( $expected, $ss->read( $length ) );
- }
-
- /** @expectedException \InvalidArgumentException */
- public function testReadBeyondEnd() {
- $ss = new StringStream( 'abc' );
- $ss->seek( 1, SEEK_END );
- }
-
- /** @expectedException \InvalidArgumentException */
- public function testReadBeforeStart() {
- $ss = new StringStream( 'abc' );
- $ss->seek( -1 );
- }
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Revision;
-
-use MediaWiki\Revision\FallbackSlotRoleHandler;
-use MediaWikiTestCase;
-use Title;
-
-/**
- * @covers \MediaWiki\Revision\FallbackSlotRoleHandler
- */
-class FallbackSlotRoleHandlerTest extends MediaWikiTestCase {
-
- /**
- * @return Title
- */
- private function makeBlankTitleObject() {
- return $this->createMock( Title::class );
- }
-
- /**
- * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::__construct
- * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::getRole()
- * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::getNameMessageKey()
- * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::getDefaultModel()
- * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::getOutputLayoutHints()
- */
- public function testConstruction() {
- $handler = new FallbackSlotRoleHandler( 'foo' );
- $this->assertSame( 'foo', $handler->getRole() );
- $this->assertSame( 'slot-name-foo', $handler->getNameMessageKey() );
-
- $title = $this->makeBlankTitleObject();
- $this->assertSame( CONTENT_MODEL_TEXT, $handler->getDefaultModel( $title ) );
-
- $hints = $handler->getOutputLayoutHints();
- $this->assertArrayHasKey( 'display', $hints );
- $this->assertArrayHasKey( 'region', $hints );
- $this->assertArrayHasKey( 'placement', $hints );
- }
-
- /**
- * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::isAllowedModel()
- */
- public function testIsAllowedModel() {
- $handler = new FallbackSlotRoleHandler( 'foo', 'FooModel' );
-
- // For the fallback handler, no models are allowed
- $title = $this->makeBlankTitleObject();
- $this->assertFalse( $handler->isAllowedModel( 'FooModel', $title ) );
- $this->assertFalse( $handler->isAllowedModel( 'QuaxModel', $title ) );
- }
-
- /**
- * @covers \MediaWiki\Revision\SlotRoleHandler::isAllowedModel()
- */
- public function testIsAllowedOn() {
- $handler = new FallbackSlotRoleHandler( 'foo', 'FooModel' );
-
- $title = $this->makeBlankTitleObject();
- $this->assertFalse( $handler->isAllowedOn( $title ) );
- }
-
- /**
- * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::supportsArticleCount()
- */
- public function testSupportsArticleCount() {
- $handler = new FallbackSlotRoleHandler( 'foo', 'FooModel' );
-
- $this->assertFalse( $handler->supportsArticleCount() );
- }
-
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Revision;
-
-use MediaWiki\Revision\SlotRoleHandler;
-use MediaWikiTestCase;
-use Title;
-
-/**
- * @covers \MediaWiki\Revision\SlotRoleHandler
- */
-class SlotRoleHandlerTest extends MediaWikiTestCase {
-
- /**
- * @return Title
- */
- private function makeBlankTitleObject() {
- return $this->createMock( Title::class );
- }
-
- /**
- * @covers \MediaWiki\Revision\SlotRoleHandler::__construct
- * @covers \MediaWiki\Revision\SlotRoleHandler::getRole()
- * @covers \MediaWiki\Revision\SlotRoleHandler::getNameMessageKey()
- * @covers \MediaWiki\Revision\SlotRoleHandler::getDefaultModel()
- * @covers \MediaWiki\Revision\SlotRoleHandler::getOutputLayoutHints()
- */
- public function testConstruction() {
- $handler = new SlotRoleHandler( 'foo', 'FooModel', [ 'frob' => 'niz' ] );
- $this->assertSame( 'foo', $handler->getRole() );
- $this->assertSame( 'slot-name-foo', $handler->getNameMessageKey() );
-
- $title = $this->makeBlankTitleObject();
- $this->assertSame( 'FooModel', $handler->getDefaultModel( $title ) );
-
- $hints = $handler->getOutputLayoutHints();
- $this->assertArrayHasKey( 'frob', $hints );
- $this->assertSame( 'niz', $hints['frob'] );
-
- $this->assertArrayHasKey( 'display', $hints );
- $this->assertArrayHasKey( 'region', $hints );
- $this->assertArrayHasKey( 'placement', $hints );
- }
-
- /**
- * @covers \MediaWiki\Revision\SlotRoleHandler::isAllowedModel()
- */
- public function testIsAllowedModel() {
- $handler = new SlotRoleHandler( 'foo', 'FooModel' );
-
- $title = $this->makeBlankTitleObject();
- $this->assertTrue( $handler->isAllowedModel( 'FooModel', $title ) );
- $this->assertFalse( $handler->isAllowedModel( 'QuaxModel', $title ) );
- }
-
- /**
- * @covers \MediaWiki\Revision\SlotRoleHandler::supportsArticleCount()
- */
- public function testSupportsArticleCount() {
- $handler = new SlotRoleHandler( 'foo', 'FooModel' );
-
- $this->assertFalse( $handler->supportsArticleCount() );
- }
-
-}
+++ /dev/null
-<?php
-
-/**
- * @coversNothing
- */
-class ServiceWiringTest extends MediaWikiTestCase {
- public function testServicesAreSorted() {
- global $IP;
- $services = array_keys( require "$IP/includes/ServiceWiring.php" );
- $sortedServices = $services;
- natcasesort( $sortedServices );
-
- $this->assertSame( $sortedServices, $services,
- 'Please keep services sorted alphabetically' );
- }
-}
+++ /dev/null
-<?php
-
-class SiteConfigurationTest extends MediaWikiTestCase {
-
- /**
- * @var SiteConfiguration
- */
- protected $mConf;
-
- protected function setUp() {
- parent::setUp();
-
- $this->mConf = new SiteConfiguration;
-
- $this->mConf->suffixes = [ 'wikipedia' => 'wiki' ];
- $this->mConf->wikis = [ 'enwiki', 'dewiki', 'frwiki' ];
- $this->mConf->settings = [
- 'SimpleKey' => [
- 'wiki' => 'wiki',
- 'tag' => 'tag',
- 'enwiki' => 'enwiki',
- 'dewiki' => 'dewiki',
- 'frwiki' => 'frwiki',
- ],
-
- 'Fallback' => [
- 'default' => 'default',
- 'wiki' => 'wiki',
- 'tag' => 'tag',
- 'frwiki' => 'frwiki',
- 'null_wiki' => null,
- ],
-
- 'WithParams' => [
- 'default' => '$lang $site $wiki',
- ],
-
- '+SomeGlobal' => [
- 'wiki' => [
- 'wiki' => 'wiki',
- ],
- 'tag' => [
- 'tag' => 'tag',
- ],
- 'enwiki' => [
- 'enwiki' => 'enwiki',
- ],
- 'dewiki' => [
- 'dewiki' => 'dewiki',
- ],
- 'frwiki' => [
- 'frwiki' => 'frwiki',
- ],
- ],
-
- 'MergeIt' => [
- '+wiki' => [
- 'wiki' => 'wiki',
- ],
- '+tag' => [
- 'tag' => 'tag',
- ],
- 'default' => [
- 'default' => 'default',
- ],
- '+enwiki' => [
- 'enwiki' => 'enwiki',
- ],
- '+dewiki' => [
- 'dewiki' => 'dewiki',
- ],
- '+frwiki' => [
- 'frwiki' => 'frwiki',
- ],
- ],
- ];
-
- $GLOBALS['SomeGlobal'] = [ 'SomeGlobal' => 'SomeGlobal' ];
- }
-
- /**
- * This function is used as a callback within the tests below
- */
- public static function getSiteParamsCallback( $conf, $wiki ) {
- $site = null;
- $lang = null;
- foreach ( $conf->suffixes as $suffix ) {
- if ( substr( $wiki, -strlen( $suffix ) ) == $suffix ) {
- $site = $suffix;
- $lang = substr( $wiki, 0, -strlen( $suffix ) );
- break;
- }
- }
-
- return [
- 'suffix' => $site,
- 'lang' => $lang,
- 'params' => [
- 'lang' => $lang,
- 'site' => $site,
- 'wiki' => $wiki,
- ],
- 'tags' => [ 'tag' ],
- ];
- }
-
- /**
- * @covers SiteConfiguration::siteFromDB
- */
- public function testSiteFromDb() {
- $this->assertEquals(
- [ 'wikipedia', 'en' ],
- $this->mConf->siteFromDB( 'enwiki' ),
- 'siteFromDB()'
- );
- $this->assertEquals(
- [ 'wikipedia', '' ],
- $this->mConf->siteFromDB( 'wiki' ),
- 'siteFromDB() on a suffix'
- );
- $this->assertEquals(
- [ null, null ],
- $this->mConf->siteFromDB( 'wikien' ),
- 'siteFromDB() on a non-existing wiki'
- );
-
- $this->mConf->suffixes = [ 'wiki', '' ];
- $this->assertEquals(
- [ '', 'wikien' ],
- $this->mConf->siteFromDB( 'wikien' ),
- 'siteFromDB() on a non-existing wiki (2)'
- );
- }
-
- /**
- * @covers SiteConfiguration::getLocalDatabases
- */
- public function testGetLocalDatabases() {
- $this->assertEquals(
- [ 'enwiki', 'dewiki', 'frwiki' ],
- $this->mConf->getLocalDatabases(),
- 'getLocalDatabases()'
- );
- }
-
- /**
- * @covers SiteConfiguration::get
- */
- public function testGetConfVariables() {
- // Simple
- $this->assertEquals(
- 'enwiki',
- $this->mConf->get( 'SimpleKey', 'enwiki', 'wiki' ),
- 'get(): simple setting on an existing wiki'
- );
- $this->assertEquals(
- 'dewiki',
- $this->mConf->get( 'SimpleKey', 'dewiki', 'wiki' ),
- 'get(): simple setting on an existing wiki (2)'
- );
- $this->assertEquals(
- 'frwiki',
- $this->mConf->get( 'SimpleKey', 'frwiki', 'wiki' ),
- 'get(): simple setting on an existing wiki (3)'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'SimpleKey', 'wiki', 'wiki' ),
- 'get(): simple setting on an suffix'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'SimpleKey', 'eswiki', 'wiki' ),
- 'get(): simple setting on an non-existing wiki'
- );
-
- // Fallback
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'Fallback', 'enwiki', 'wiki' ),
- 'get(): fallback setting on an existing wiki'
- );
- $this->assertEquals(
- 'tag',
- $this->mConf->get( 'Fallback', 'dewiki', 'wiki', [], [ 'tag' ] ),
- 'get(): fallback setting on an existing wiki (with wiki tag)'
- );
- $this->assertEquals(
- 'frwiki',
- $this->mConf->get( 'Fallback', 'frwiki', 'wiki', [], [ 'tag' ] ),
- 'get(): no fallback if wiki has its own setting (matching tag)'
- );
- $this->assertSame(
- // Potential regression test for T192855
- null,
- $this->mConf->get( 'Fallback', 'null_wiki', 'wiki', [], [ 'tag' ] ),
- 'get(): no fallback if wiki has its own setting (matching tag and uses null)'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'Fallback', 'wiki', 'wiki' ),
- 'get(): fallback setting on an suffix'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'Fallback', 'wiki', 'wiki', [], [ 'tag' ] ),
- 'get(): fallback setting on an suffix (with wiki tag)'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'Fallback', 'eswiki', 'wiki' ),
- 'get(): fallback setting on an non-existing wiki'
- );
- $this->assertEquals(
- 'tag',
- $this->mConf->get( 'Fallback', 'eswiki', 'wiki', [], [ 'tag' ] ),
- 'get(): fallback setting on an non-existing wiki (with wiki tag)'
- );
-
- // Merging
- $common = [ 'wiki' => 'wiki', 'default' => 'default' ];
- $commonTag = [ 'tag' => 'tag', 'wiki' => 'wiki', 'default' => 'default' ];
- $this->assertEquals(
- [ 'enwiki' => 'enwiki' ] + $common,
- $this->mConf->get( 'MergeIt', 'enwiki', 'wiki' ),
- 'get(): merging setting on an existing wiki'
- );
- $this->assertEquals(
- [ 'enwiki' => 'enwiki' ] + $commonTag,
- $this->mConf->get( 'MergeIt', 'enwiki', 'wiki', [], [ 'tag' ] ),
- 'get(): merging setting on an existing wiki (with tag)'
- );
- $this->assertEquals(
- [ 'dewiki' => 'dewiki' ] + $common,
- $this->mConf->get( 'MergeIt', 'dewiki', 'wiki' ),
- 'get(): merging setting on an existing wiki (2)'
- );
- $this->assertEquals(
- [ 'dewiki' => 'dewiki' ] + $commonTag,
- $this->mConf->get( 'MergeIt', 'dewiki', 'wiki', [], [ 'tag' ] ),
- 'get(): merging setting on an existing wiki (2) (with tag)'
- );
- $this->assertEquals(
- [ 'frwiki' => 'frwiki' ] + $common,
- $this->mConf->get( 'MergeIt', 'frwiki', 'wiki' ),
- 'get(): merging setting on an existing wiki (3)'
- );
- $this->assertEquals(
- [ 'frwiki' => 'frwiki' ] + $commonTag,
- $this->mConf->get( 'MergeIt', 'frwiki', 'wiki', [], [ 'tag' ] ),
- 'get(): merging setting on an existing wiki (3) (with tag)'
- );
- $this->assertEquals(
- [ 'wiki' => 'wiki' ] + $common,
- $this->mConf->get( 'MergeIt', 'wiki', 'wiki' ),
- 'get(): merging setting on an suffix'
- );
- $this->assertEquals(
- [ 'wiki' => 'wiki' ] + $commonTag,
- $this->mConf->get( 'MergeIt', 'wiki', 'wiki', [], [ 'tag' ] ),
- 'get(): merging setting on an suffix (with tag)'
- );
- $this->assertEquals(
- $common,
- $this->mConf->get( 'MergeIt', 'eswiki', 'wiki' ),
- 'get(): merging setting on an non-existing wiki'
- );
- $this->assertEquals(
- $commonTag,
- $this->mConf->get( 'MergeIt', 'eswiki', 'wiki', [], [ 'tag' ] ),
- 'get(): merging setting on an non-existing wiki (with tag)'
- );
- }
-
- /**
- * @covers SiteConfiguration::siteFromDB
- */
- public function testSiteFromDbWithCallback() {
- $this->mConf->siteParamsCallback = 'SiteConfigurationTest::getSiteParamsCallback';
-
- $this->assertEquals(
- [ 'wiki', 'en' ],
- $this->mConf->siteFromDB( 'enwiki' ),
- 'siteFromDB() with callback'
- );
- $this->assertEquals(
- [ 'wiki', '' ],
- $this->mConf->siteFromDB( 'wiki' ),
- 'siteFromDB() with callback on a suffix'
- );
- $this->assertEquals(
- [ null, null ],
- $this->mConf->siteFromDB( 'wikien' ),
- 'siteFromDB() with callback on a non-existing wiki'
- );
- }
-
- /**
- * @covers SiteConfiguration::get
- */
- public function testParameterReplacement() {
- $this->mConf->siteParamsCallback = 'SiteConfigurationTest::getSiteParamsCallback';
-
- $this->assertEquals(
- 'en wiki enwiki',
- $this->mConf->get( 'WithParams', 'enwiki', 'wiki' ),
- 'get(): parameter replacement on an existing wiki'
- );
- $this->assertEquals(
- 'de wiki dewiki',
- $this->mConf->get( 'WithParams', 'dewiki', 'wiki' ),
- 'get(): parameter replacement on an existing wiki (2)'
- );
- $this->assertEquals(
- 'fr wiki frwiki',
- $this->mConf->get( 'WithParams', 'frwiki', 'wiki' ),
- 'get(): parameter replacement on an existing wiki (3)'
- );
- $this->assertEquals(
- ' wiki wiki',
- $this->mConf->get( 'WithParams', 'wiki', 'wiki' ),
- 'get(): parameter replacement on an suffix'
- );
- $this->assertEquals(
- 'es wiki eswiki',
- $this->mConf->get( 'WithParams', 'eswiki', 'wiki' ),
- 'get(): parameter replacement on an non-existing wiki'
- );
- }
-
- /**
- * @covers SiteConfiguration::getAll
- */
- public function testGetAllGlobals() {
- $this->mConf->siteParamsCallback = 'SiteConfigurationTest::getSiteParamsCallback';
-
- $getall = [
- 'SimpleKey' => 'enwiki',
- 'Fallback' => 'tag',
- 'WithParams' => 'en wiki enwiki',
- 'SomeGlobal' => [ 'enwiki' => 'enwiki' ] + $GLOBALS['SomeGlobal'],
- 'MergeIt' => [
- 'enwiki' => 'enwiki',
- 'tag' => 'tag',
- 'wiki' => 'wiki',
- 'default' => 'default'
- ],
- ];
- $this->assertEquals( $getall, $this->mConf->getAll( 'enwiki' ), 'getAll()' );
-
- $this->mConf->extractAllGlobals( 'enwiki', 'wiki' );
-
- $this->assertEquals(
- $getall['SimpleKey'],
- $GLOBALS['SimpleKey'],
- 'extractAllGlobals(): simple setting'
- );
- $this->assertEquals(
- $getall['Fallback'],
- $GLOBALS['Fallback'],
- 'extractAllGlobals(): fallback setting'
- );
- $this->assertEquals(
- $getall['WithParams'],
- $GLOBALS['WithParams'],
- 'extractAllGlobals(): parameter replacement'
- );
- $this->assertEquals(
- $getall['SomeGlobal'],
- $GLOBALS['SomeGlobal'],
- 'extractAllGlobals(): merging with global'
- );
- $this->assertEquals(
- $getall['MergeIt'],
- $GLOBALS['MergeIt'],
- 'extractAllGlobals(): merging setting'
- );
- }
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Edit;
-
-use ParserOutput;
-use MediaWikiTestCase;
-
-/**
- * @covers \MediaWiki\Edit\PreparedEdit
- */
-class PreparedEditTest extends MediaWikiTestCase {
- function testCallback() {
- $output = new ParserOutput();
- $edit = new PreparedEdit();
- $edit->parserOutputCallback = function () {
- return new ParserOutput();
- };
-
- $this->assertEquals( $output, $edit->getOutput() );
- $this->assertEquals( $output, $edit->output );
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @group Xml
- */
-class XmlSelectTest extends MediaWikiTestCase {
-
- /**
- * @var XmlSelect
- */
- protected $select;
-
- protected function setUp() {
- parent::setUp();
- $this->select = new XmlSelect();
- }
-
- protected function tearDown() {
- parent::tearDown();
- $this->select = null;
- }
-
- /**
- * @covers XmlSelect::__construct
- */
- public function testConstructWithoutParameters() {
- $this->assertEquals( '<select></select>', $this->select->getHTML() );
- }
-
- /**
- * Parameters are $name (false), $id (false), $default (false)
- * @dataProvider provideConstructionParameters
- * @covers XmlSelect::__construct
- */
- public function testConstructParameters( $name, $id, $default, $expected ) {
- $this->select = new XmlSelect( $name, $id, $default );
- $this->assertEquals( $expected, $this->select->getHTML() );
- }
-
- /**
- * Provide parameters for testConstructParameters() which use three
- * parameters:
- * - $name (default: false)
- * - $id (default: false)
- * - $default (default: false)
- * Provides a fourth parameters representing the expected HTML output
- */
- public static function provideConstructionParameters() {
- return [
- /**
- * Values are set following a 3-bit Gray code where two successive
- * values differ by only one value.
- * See https://en.wikipedia.org/wiki/Gray_code
- */
- # $name $id $default
- [ false, false, false, '<select></select>' ],
- [ false, false, 'foo', '<select></select>' ],
- [ false, 'id', 'foo', '<select id="id"></select>' ],
- [ false, 'id', false, '<select id="id"></select>' ],
- [ 'name', 'id', false, '<select name="name" id="id"></select>' ],
- [ 'name', 'id', 'foo', '<select name="name" id="id"></select>' ],
- [ 'name', false, 'foo', '<select name="name"></select>' ],
- [ 'name', false, false, '<select name="name"></select>' ],
- ];
- }
-
- /**
- * @covers XmlSelect::addOption
- */
- public function testAddOption() {
- $this->select->addOption( 'foo' );
- $this->assertEquals(
- '<select><option value="foo">foo</option></select>',
- $this->select->getHTML()
- );
- }
-
- /**
- * @covers XmlSelect::addOption
- */
- public function testAddOptionWithDefault() {
- $this->select->addOption( 'foo', true );
- $this->assertEquals(
- '<select><option value="1">foo</option></select>',
- $this->select->getHTML()
- );
- }
-
- /**
- * @covers XmlSelect::addOption
- */
- public function testAddOptionWithFalse() {
- $this->select->addOption( 'foo', false );
- $this->assertEquals(
- '<select><option value="foo">foo</option></select>',
- $this->select->getHTML()
- );
- }
-
- /**
- * @covers XmlSelect::addOption
- */
- public function testAddOptionWithValueZero() {
- $this->select->addOption( 'foo', 0 );
- $this->assertEquals(
- '<select><option value="0">foo</option></select>',
- $this->select->getHTML()
- );
- }
-
- /**
- * @covers XmlSelect::setDefault
- */
- public function testSetDefault() {
- $this->select->setDefault( 'bar1' );
- $this->select->addOption( 'foo1' );
- $this->select->addOption( 'bar1' );
- $this->select->addOption( 'foo2' );
- $this->assertEquals(
- '<select><option value="foo1">foo1</option>' . "\n" .
- '<option value="bar1" selected="">bar1</option>' . "\n" .
- '<option value="foo2">foo2</option></select>', $this->select->getHTML() );
- }
-
- /**
- * Adding default later on should set the correct selection or
- * raise an exception.
- * To handle this, we need to render the options in getHtml()
- * @covers XmlSelect::setDefault
- */
- public function testSetDefaultAfterAddingOptions() {
- $this->select->addOption( 'foo1' );
- $this->select->addOption( 'bar1' );
- $this->select->addOption( 'foo2' );
- $this->select->setDefault( 'bar1' ); # setting default after adding options
- $this->assertEquals(
- '<select><option value="foo1">foo1</option>' . "\n" .
- '<option value="bar1" selected="">bar1</option>' . "\n" .
- '<option value="foo2">foo2</option></select>', $this->select->getHTML() );
- }
-
- /**
- * @covers XmlSelect::setAttribute
- * @covers XmlSelect::getAttribute
- */
- public function testGetAttributes() {
- # create some attributes
- $this->select->setAttribute( 'dummy', 0x777 );
- $this->select->setAttribute( 'string', 'euro €' );
- $this->select->setAttribute( 1911, 'razor' );
-
- # verify we can retrieve them
- $this->assertEquals(
- $this->select->getAttribute( 'dummy' ),
- 0x777
- );
- $this->assertEquals(
- $this->select->getAttribute( 'string' ),
- 'euro €'
- );
- $this->assertEquals(
- $this->select->getAttribute( 1911 ),
- 'razor'
- );
-
- # inexistent keys should give us 'null'
- $this->assertEquals(
- $this->select->getAttribute( 'I DO NOT EXIT' ),
- null
- );
-
- # verify string / integer
- $this->assertEquals(
- $this->select->getAttribute( '1911' ),
- 'razor'
- );
- $this->assertEquals(
- $this->select->getAttribute( 'dummy' ),
- 0x777
- );
- }
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Auth;
-
-/**
- * @group AuthManager
- * @covers \MediaWiki\Auth\AuthenticationResponse
- */
-class AuthenticationResponseTest extends \MediaWikiTestCase {
- /**
- * @dataProvider provideConstructors
- * @param string $constructor
- * @param array $args
- * @param array|Exception $expect
- */
- public function testConstructors( $constructor, $args, $expect ) {
- if ( is_array( $expect ) ) {
- $res = new AuthenticationResponse();
- $res->messageType = 'warning';
- foreach ( $expect as $field => $value ) {
- $res->$field = $value;
- }
- $ret = call_user_func_array( "MediaWiki\\Auth\\AuthenticationResponse::$constructor", $args );
- $this->assertEquals( $res, $ret );
- } else {
- try {
- call_user_func_array( "MediaWiki\\Auth\\AuthenticationResponse::$constructor", $args );
- $this->fail( 'Expected exception not thrown' );
- } catch ( \Exception $ex ) {
- $this->assertEquals( $expect, $ex );
- }
- }
- }
-
- public function provideConstructors() {
- $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
- $msg = new \Message( 'mainpage' );
-
- return [
- [ 'newPass', [], [
- 'status' => AuthenticationResponse::PASS,
- ] ],
- [ 'newPass', [ 'name' ], [
- 'status' => AuthenticationResponse::PASS,
- 'username' => 'name',
- ] ],
- [ 'newPass', [ 'name', null ], [
- 'status' => AuthenticationResponse::PASS,
- 'username' => 'name',
- ] ],
-
- [ 'newFail', [ $msg ], [
- 'status' => AuthenticationResponse::FAIL,
- 'message' => $msg,
- 'messageType' => 'error',
- ] ],
-
- [ 'newRestart', [ $msg ], [
- 'status' => AuthenticationResponse::RESTART,
- 'message' => $msg,
- ] ],
-
- [ 'newAbstain', [], [
- 'status' => AuthenticationResponse::ABSTAIN,
- ] ],
-
- [ 'newUI', [ [ $req ], $msg ], [
- 'status' => AuthenticationResponse::UI,
- 'neededRequests' => [ $req ],
- 'message' => $msg,
- 'messageType' => 'warning',
- ] ],
-
- [ 'newUI', [ [ $req ], $msg, 'warning' ], [
- 'status' => AuthenticationResponse::UI,
- 'neededRequests' => [ $req ],
- 'message' => $msg,
- 'messageType' => 'warning',
- ] ],
-
- [ 'newUI', [ [ $req ], $msg, 'error' ], [
- 'status' => AuthenticationResponse::UI,
- 'neededRequests' => [ $req ],
- 'message' => $msg,
- 'messageType' => 'error',
- ] ],
- [ 'newUI', [ [], $msg ],
- new \InvalidArgumentException( '$reqs may not be empty' )
- ],
-
- [ 'newRedirect', [ [ $req ], 'http://example.org/redir' ], [
- 'status' => AuthenticationResponse::REDIRECT,
- 'neededRequests' => [ $req ],
- 'redirectTarget' => 'http://example.org/redir',
- ] ],
- [
- 'newRedirect',
- [ [ $req ], 'http://example.org/redir', [ 'foo' => 'bar' ] ],
- [
- 'status' => AuthenticationResponse::REDIRECT,
- 'neededRequests' => [ $req ],
- 'redirectTarget' => 'http://example.org/redir',
- 'redirectApiData' => [ 'foo' => 'bar' ],
- ]
- ],
- [ 'newRedirect', [ [], 'http://example.org/redir' ],
- new \InvalidArgumentException( '$reqs may not be empty' )
- ],
- ];
- }
-
-}
+++ /dev/null
-<?php
-
-/**
- * @covers ChangesListFilterGroup
- */
-class ChangesListFilterGroupTest extends MediaWikiTestCase {
- /**
- * phpcs:disable Generic.Files.LineLength
- * @expectedException MWException
- * @expectedExceptionMessage Group names may not contain '_'. Use the naming convention: 'camelCase'
- * phpcs:enable
- */
- public function testReservedCharacter() {
- new MockChangesListFilterGroup(
- [
- 'type' => 'some_type',
- 'name' => 'group_name',
- 'priority' => 1,
- 'filters' => [],
- ]
- );
- }
-
- public function testAutoPriorities() {
- $group = new MockChangesListFilterGroup(
- [
- 'type' => 'some_type',
- 'name' => 'groupName',
- 'isFullCoverage' => true,
- 'priority' => 1,
- 'filters' => [
- [ 'name' => 'hidefoo' ],
- [ 'name' => 'hidebar' ],
- [ 'name' => 'hidebaz' ],
- ],
- ]
- );
-
- $filters = $group->getFilters();
- $this->assertEquals(
- [
- -2,
- -3,
- -4,
- ],
- array_map(
- function ( $f ) {
- return $f->getPriority();
- },
- array_values( $filters )
- )
- );
- }
-
- // Get without warnings
- public function testGetFilter() {
- $group = new MockChangesListFilterGroup(
- [
- 'type' => 'some_type',
- 'name' => 'groupName',
- 'isFullCoverage' => true,
- 'priority' => 1,
- 'filters' => [
- [ 'name' => 'foo' ],
- ],
- ]
- );
-
- $this->assertEquals(
- 'foo',
- $group->getFilter( 'foo' )->getName()
- );
-
- $this->assertEquals(
- null,
- $group->getFilter( 'bar' )
- );
- }
-}
+++ /dev/null
-<?php
-
-class HashConfigTest extends MediaWikiTestCase {
-
- /**
- * @covers HashConfig::newInstance
- */
- public function testNewInstance() {
- $conf = HashConfig::newInstance();
- $this->assertInstanceOf( HashConfig::class, $conf );
- }
-
- /**
- * @covers HashConfig::__construct
- */
- public function testConstructor() {
- $conf = new HashConfig();
- $this->assertInstanceOf( HashConfig::class, $conf );
-
- // Test passing arguments to the constructor
- $conf2 = new HashConfig( [
- 'one' => '1',
- ] );
- $this->assertEquals( '1', $conf2->get( 'one' ) );
- }
-
- /**
- * @covers HashConfig::get
- */
- public function testGet() {
- $conf = new HashConfig( [
- 'one' => '1',
- ] );
- $this->assertEquals( '1', $conf->get( 'one' ) );
- $this->setExpectedException( ConfigException::class, 'HashConfig::get: undefined option' );
- $conf->get( 'two' );
- }
-
- /**
- * @covers HashConfig::has
- */
- public function testHas() {
- $conf = new HashConfig( [
- 'one' => '1',
- ] );
- $this->assertTrue( $conf->has( 'one' ) );
- $this->assertFalse( $conf->has( 'two' ) );
- }
-
- /**
- * @covers HashConfig::set
- */
- public function testSet() {
- $conf = new HashConfig( [
- 'one' => '1',
- ] );
- $conf->set( 'two', '2' );
- $this->assertEquals( '2', $conf->get( 'two' ) );
- // Check that set overwrites
- $conf->set( 'one', '3' );
- $this->assertEquals( '3', $conf->get( 'one' ) );
- }
-}
+++ /dev/null
-<?php
-
-class MultiConfigTest extends MediaWikiTestCase {
-
- /**
- * Tests that settings are fetched in the right order
- *
- * @covers MultiConfig::__construct
- * @covers MultiConfig::get
- */
- public function testGet() {
- $multi = new MultiConfig( [
- new HashConfig( [ 'foo' => 'bar' ] ),
- new HashConfig( [ 'foo' => 'baz', 'bar' => 'foo' ] ),
- new HashConfig( [ 'bar' => 'baz' ] ),
- ] );
-
- $this->assertEquals( 'bar', $multi->get( 'foo' ) );
- $this->assertEquals( 'foo', $multi->get( 'bar' ) );
- $this->setExpectedException( ConfigException::class, 'MultiConfig::get: undefined option:' );
- $multi->get( 'notset' );
- }
-
- /**
- * @covers MultiConfig::has
- */
- public function testHas() {
- $conf = new MultiConfig( [
- new HashConfig( [ 'foo' => 'foo' ] ),
- new HashConfig( [ 'something' => 'bleh' ] ),
- new HashConfig( [ 'meh' => 'eh' ] ),
- ] );
-
- $this->assertTrue( $conf->has( 'foo' ) );
- $this->assertTrue( $conf->has( 'something' ) );
- $this->assertTrue( $conf->has( 'meh' ) );
- $this->assertFalse( $conf->has( 'what' ) );
- }
-}
+++ /dev/null
-<?php
-
-use MediaWiki\Config\ServiceOptions;
-
-/**
- * @coversDefaultClass \MediaWiki\Config\ServiceOptions
- */
-class ServiceOptionsTest extends MediaWikiTestCase {
- public static $testObj;
-
- public static function setUpBeforeClass() {
- parent::setUpBeforeClass();
-
- self::$testObj = new stdclass();
- }
-
- /**
- * @dataProvider provideConstructor
- * @covers ::__construct
- * @covers ::assertRequiredOptions
- * @covers ::get
- */
- public function testConstructor( $expected, $keys, ...$sources ) {
- $options = new ServiceOptions( $keys, ...$sources );
-
- foreach ( $expected as $key => $val ) {
- $this->assertSame( $val, $options->get( $key ) );
- }
-
- // This is lumped in the same test because there's no support for depending on a test that
- // has a data provider.
- $options->assertRequiredOptions( array_keys( $expected ) );
-
- // Suppress warning if no assertions were run. This is expected for empty arguments.
- $this->assertTrue( true );
- }
-
- public function provideConstructor() {
- return [
- 'No keys' => [ [], [], [ 'a' => 'aval' ] ],
- 'Simple array source' => [
- [ 'a' => 'aval', 'b' => 'bval' ],
- [ 'a', 'b' ],
- [ 'a' => 'aval', 'b' => 'bval', 'c' => 'cval' ],
- ],
- 'Simple HashConfig source' => [
- [ 'a' => 'aval', 'b' => 'bval' ],
- [ 'a', 'b' ],
- new HashConfig( [ 'a' => 'aval', 'b' => 'bval', 'c' => 'cval' ] ),
- ],
- 'Three different sources' => [
- [ 'a' => 'aval', 'b' => 'bval' ],
- [ 'a', 'b' ],
- [ 'z' => 'zval' ],
- new HashConfig( [ 'a' => 'aval', 'c' => 'cval' ] ),
- [ 'b' => 'bval', 'd' => 'dval' ],
- ],
- 'null key' => [
- [ 'a' => null ],
- [ 'a' ],
- [ 'a' => null ],
- ],
- 'Numeric option name' => [
- [ '0' => 'nothing' ],
- [ '0' ],
- [ '0' => 'nothing' ],
- ],
- 'Multiple sources for one key' => [
- [ 'a' => 'winner' ],
- [ 'a' ],
- [ 'a' => 'winner' ],
- [ 'a' => 'second place' ],
- ],
- 'Object value is passed by reference' => [
- [ 'a' => self::$testObj ],
- [ 'a' ],
- [ 'a' => self::$testObj ],
- ],
- ];
- }
-
- /**
- * @covers ::__construct
- */
- public function testKeyNotFound() {
- $this->setExpectedException( InvalidArgumentException::class,
- 'Key "a" not found in input sources' );
-
- new ServiceOptions( [ 'a' ], [ 'b' => 'bval' ], [ 'c' => 'cval' ] );
- }
-
- /**
- * @covers ::__construct
- * @covers ::assertRequiredOptions
- */
- public function testOutOfOrderAssertRequiredOptions() {
- $options = new ServiceOptions( [ 'a', 'b' ], [ 'a' => '', 'b' => '' ] );
- $options->assertRequiredOptions( [ 'b', 'a' ] );
- $this->assertTrue( true, 'No exception thrown' );
- }
-
- /**
- * @covers ::__construct
- * @covers ::get
- */
- public function testGetUnrecognized() {
- $this->setExpectedException( InvalidArgumentException::class,
- 'Unrecognized option "b"' );
-
- $options = new ServiceOptions( [ 'a' ], [ 'a' => '' ] );
- $options->get( 'b' );
- }
-
- /**
- * @covers ::__construct
- * @covers ::assertRequiredOptions
- */
- public function testExtraKeys() {
- $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
- 'Precondition failed: Unsupported options passed: b, c!' );
-
- $options = new ServiceOptions( [ 'a', 'b', 'c' ], [ 'a' => '', 'b' => '', 'c' => '' ] );
- $options->assertRequiredOptions( [ 'a' ] );
- }
-
- /**
- * @covers ::__construct
- * @covers ::assertRequiredOptions
- */
- public function testMissingKeys() {
- $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
- 'Precondition failed: Required options missing: a, b!' );
-
- $options = new ServiceOptions( [ 'c' ], [ 'c' => '' ] );
- $options->assertRequiredOptions( [ 'a', 'b', 'c' ] );
- }
-
- /**
- * @covers ::__construct
- * @covers ::assertRequiredOptions
- */
- public function testExtraAndMissingKeys() {
- $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
- 'Precondition failed: Unsupported options passed: b! Required options missing: c!' );
-
- $options = new ServiceOptions( [ 'a', 'b' ], [ 'a' => '', 'b' => '' ] );
- $options->assertRequiredOptions( [ 'a', 'c' ] );
- }
-}
+++ /dev/null
-<?php
-
-class JsonContentHandlerTest extends MediaWikiTestCase {
-
- /**
- * @covers JsonContentHandler::makeEmptyContent
- */
- public function testMakeEmptyContent() {
- $handler = new JsonContentHandler();
- $content = $handler->makeEmptyContent();
- $this->assertInstanceOf( JsonContent::class, $content );
- $this->assertTrue( $content->isValid() );
- }
-}
+++ /dev/null
-<?php
-/**
- * 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
- */
-
-namespace MediaWiki\Logger;
-
-use MediaWikiTestCase;
-use Wikimedia\TestingAccessWrapper;
-
-class MonologSpiTest extends MediaWikiTestCase {
-
- /**
- * @covers MediaWiki\Logger\MonologSpi::mergeConfig
- */
- public function testMergeConfig() {
- $base = [
- 'loggers' => [
- '@default' => [
- 'processors' => [ 'constructor' ],
- 'handlers' => [ 'constructor' ],
- ],
- ],
- 'processors' => [
- 'constructor' => [
- 'class' => 'constructor',
- ],
- ],
- 'handlers' => [
- 'constructor' => [
- 'class' => 'constructor',
- 'formatter' => 'constructor',
- ],
- ],
- 'formatters' => [
- 'constructor' => [
- 'class' => 'constructor',
- ],
- ],
- ];
-
- $fixture = new MonologSpi( $base );
- $this->assertSame(
- $base,
- TestingAccessWrapper::newFromObject( $fixture )->config
- );
-
- $fixture->mergeConfig( [
- 'loggers' => [
- 'merged' => [
- 'processors' => [ 'merged' ],
- 'handlers' => [ 'merged' ],
- ],
- ],
- 'processors' => [
- 'merged' => [
- 'class' => 'merged',
- ],
- ],
- 'magic' => [
- 'idkfa' => [ 'xyzzy' ],
- ],
- 'handlers' => [
- 'merged' => [
- 'class' => 'merged',
- 'formatter' => 'merged',
- ],
- ],
- 'formatters' => [
- 'merged' => [
- 'class' => 'merged',
- ],
- ],
- ] );
- $this->assertSame(
- [
- 'loggers' => [
- '@default' => [
- 'processors' => [ 'constructor' ],
- 'handlers' => [ 'constructor' ],
- ],
- 'merged' => [
- 'processors' => [ 'merged' ],
- 'handlers' => [ 'merged' ],
- ],
- ],
- 'processors' => [
- 'constructor' => [
- 'class' => 'constructor',
- ],
- 'merged' => [
- 'class' => 'merged',
- ],
- ],
- 'handlers' => [
- 'constructor' => [
- 'class' => 'constructor',
- 'formatter' => 'constructor',
- ],
- 'merged' => [
- 'class' => 'merged',
- 'formatter' => 'merged',
- ],
- ],
- 'formatters' => [
- 'constructor' => [
- 'class' => 'constructor',
- ],
- 'merged' => [
- 'class' => 'merged',
- ],
- ],
- 'magic' => [
- 'idkfa' => [ 'xyzzy' ],
- ],
- ],
- TestingAccessWrapper::newFromObject( $fixture )->config
- );
- }
-
-}
+++ /dev/null
-<?php
-/**
- * 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
- */
-
-namespace MediaWiki\Logger\Monolog;
-
-use MediaWikiTestCase;
-use PHPUnit_Framework_Error_Notice;
-
-/**
- * @covers \MediaWiki\Logger\Monolog\AvroFormatter
- */
-class AvroFormatterTest extends MediaWikiTestCase {
-
- protected function setUp() {
- if ( !class_exists( 'AvroStringIO' ) ) {
- $this->markTestSkipped( 'Avro is required for the AvroFormatterTest' );
- }
- parent::setUp();
- }
-
- public function testSchemaNotAvailable() {
- $formatter = new AvroFormatter( [] );
- $this->setExpectedException(
- 'PHPUnit_Framework_Error_Notice',
- "The schema for channel 'marty' is not available"
- );
- $formatter->format( [ 'channel' => 'marty' ] );
- }
-
- public function testSchemaNotAvailableReturnValue() {
- $formatter = new AvroFormatter( [] );
- $noticeEnabled = PHPUnit_Framework_Error_Notice::$enabled;
- // disable conversion of notices
- PHPUnit_Framework_Error_Notice::$enabled = false;
- // have to keep the user notice from being output
- \Wikimedia\suppressWarnings();
- $res = $formatter->format( [ 'channel' => 'marty' ] );
- \Wikimedia\restoreWarnings();
- PHPUnit_Framework_Error_Notice::$enabled = $noticeEnabled;
- $this->assertNull( $res );
- }
-
- public function testDoesSomethingWhenSchemaAvailable() {
- $formatter = new AvroFormatter( [
- 'string' => [
- 'schema' => [ 'type' => 'string' ],
- 'revision' => 1010101,
- ]
- ] );
- $res = $formatter->format( [
- 'channel' => 'string',
- 'context' => 'better to be',
- ] );
- $this->assertNotNull( $res );
- // basically just tell us if avro changes its string encoding, or if
- // we completely fail to generate a log message.
- $this->assertEquals( 'AAAAAAAAD2m1GGJldHRlciB0byBiZQ==', base64_encode( $res ) );
- }
-}
+++ /dev/null
-<?php
-/**
- * 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
- */
-
-namespace MediaWiki\Logger\Monolog;
-
-use MediaWikiTestCase;
-use Monolog\Logger;
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * @covers \MediaWiki\Logger\Monolog\KafkaHandler
- */
-class KafkaHandlerTest extends MediaWikiTestCase {
-
- protected function setUp() {
- if ( !class_exists( 'Monolog\Handler\AbstractProcessingHandler' )
- || !class_exists( 'Kafka\Produce' )
- ) {
- $this->markTestSkipped( 'Monolog and Kafka are required for the KafkaHandlerTest' );
- }
-
- parent::setUp();
- }
-
- public function topicNamingProvider() {
- return [
- [ [], 'monolog_foo' ],
- [ [ 'alias' => [ 'foo' => 'bar' ] ], 'bar' ]
- ];
- }
-
- /**
- * @dataProvider topicNamingProvider
- */
- public function testTopicNaming( $options, $expect ) {
- $produce = $this->getMockBuilder( 'Kafka\Produce' )
- ->disableOriginalConstructor()
- ->getMock();
- $produce->expects( $this->any() )
- ->method( 'getAvailablePartitions' )
- ->will( $this->returnValue( [ 'A' ] ) );
- $produce->expects( $this->once() )
- ->method( 'setMessages' )
- ->with( $expect, $this->anything(), $this->anything() );
- $produce->expects( $this->any() )
- ->method( 'send' )
- ->will( $this->returnValue( true ) );
-
- $handler = new KafkaHandler( $produce, $options );
- $handler->handle( [
- 'channel' => 'foo',
- 'level' => Logger::EMERGENCY,
- 'extra' => [],
- 'context' => [],
- ] );
- }
-
- public function swallowsExceptionsWhenRequested() {
- return [
- // defaults to false
- [ [], true ],
- // also try false explicitly
- [ [ 'swallowExceptions' => false ], true ],
- // turn it on
- [ [ 'swallowExceptions' => true ], false ],
- ];
- }
-
- /**
- * @dataProvider swallowsExceptionsWhenRequested
- */
- public function testGetAvailablePartitionsException( $options, $expectException ) {
- $produce = $this->getMockBuilder( 'Kafka\Produce' )
- ->disableOriginalConstructor()
- ->getMock();
- $produce->expects( $this->any() )
- ->method( 'getAvailablePartitions' )
- ->will( $this->throwException( new \Kafka\Exception ) );
- $produce->expects( $this->any() )
- ->method( 'send' )
- ->will( $this->returnValue( true ) );
-
- if ( $expectException ) {
- $this->setExpectedException( 'Kafka\Exception' );
- }
-
- $handler = new KafkaHandler( $produce, $options );
- $handler->handle( [
- 'channel' => 'foo',
- 'level' => Logger::EMERGENCY,
- 'extra' => [],
- 'context' => [],
- ] );
-
- if ( !$expectException ) {
- $this->assertTrue( true, 'no exception was thrown' );
- }
- }
-
- /**
- * @dataProvider swallowsExceptionsWhenRequested
- */
- public function testSendException( $options, $expectException ) {
- $produce = $this->getMockBuilder( 'Kafka\Produce' )
- ->disableOriginalConstructor()
- ->getMock();
- $produce->expects( $this->any() )
- ->method( 'getAvailablePartitions' )
- ->will( $this->returnValue( [ 'A' ] ) );
- $produce->expects( $this->any() )
- ->method( 'send' )
- ->will( $this->throwException( new \Kafka\Exception ) );
-
- if ( $expectException ) {
- $this->setExpectedException( 'Kafka\Exception' );
- }
-
- $handler = new KafkaHandler( $produce, $options );
- $handler->handle( [
- 'channel' => 'foo',
- 'level' => Logger::EMERGENCY,
- 'extra' => [],
- 'context' => [],
- ] );
-
- if ( !$expectException ) {
- $this->assertTrue( true, 'no exception was thrown' );
- }
- }
-
- public function testHandlesNullFormatterResult() {
- $produce = $this->getMockBuilder( 'Kafka\Produce' )
- ->disableOriginalConstructor()
- ->getMock();
- $produce->expects( $this->any() )
- ->method( 'getAvailablePartitions' )
- ->will( $this->returnValue( [ 'A' ] ) );
- $mockMethod = $produce->expects( $this->exactly( 2 ) )
- ->method( 'setMessages' );
- $produce->expects( $this->any() )
- ->method( 'send' )
- ->will( $this->returnValue( true ) );
- // evil hax
- $matcher = TestingAccessWrapper::newFromObject( $mockMethod )->matcher;
- TestingAccessWrapper::newFromObject( $matcher )->parametersMatcher =
- new \PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters( [
- [ $this->anything(), $this->anything(), [ 'words' ] ],
- [ $this->anything(), $this->anything(), [ 'lines' ] ]
- ] );
-
- $formatter = $this->createMock( \Monolog\Formatter\FormatterInterface::class );
- $formatter->expects( $this->any() )
- ->method( 'format' )
- ->will( $this->onConsecutiveCalls( 'words', null, 'lines' ) );
-
- $handler = new KafkaHandler( $produce, [] );
- $handler->setFormatter( $formatter );
- for ( $i = 0; $i < 3; ++$i ) {
- $handler->handle( [
- 'channel' => 'foo',
- 'level' => Logger::EMERGENCY,
- 'extra' => [],
- 'context' => [],
- ] );
- }
- }
-
- public function testBatchHandlesNullFormatterResult() {
- $produce = $this->getMockBuilder( 'Kafka\Produce' )
- ->disableOriginalConstructor()
- ->getMock();
- $produce->expects( $this->any() )
- ->method( 'getAvailablePartitions' )
- ->will( $this->returnValue( [ 'A' ] ) );
- $produce->expects( $this->once() )
- ->method( 'setMessages' )
- ->with( $this->anything(), $this->anything(), [ 'words', 'lines' ] );
- $produce->expects( $this->any() )
- ->method( 'send' )
- ->will( $this->returnValue( true ) );
-
- $formatter = $this->createMock( \Monolog\Formatter\FormatterInterface::class );
- $formatter->expects( $this->any() )
- ->method( 'format' )
- ->will( $this->onConsecutiveCalls( 'words', null, 'lines' ) );
-
- $handler = new KafkaHandler( $produce, [] );
- $handler->setFormatter( $formatter );
- $handler->handleBatch( [
- [
- 'channel' => 'foo',
- 'level' => Logger::EMERGENCY,
- 'extra' => [],
- 'context' => [],
- ],
- [
- 'channel' => 'foo',
- 'level' => Logger::EMERGENCY,
- 'extra' => [],
- 'context' => [],
- ],
- [
- 'channel' => 'foo',
- 'level' => Logger::EMERGENCY,
- 'extra' => [],
- 'context' => [],
- ],
- ] );
- }
-}
+++ /dev/null
-<?php
-/**
- * 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
- */
-
-namespace MediaWiki\Logger\Monolog;
-
-use AssertionError;
-use InvalidArgumentException;
-use LengthException;
-use LogicException;
-use MediaWikiTestCase;
-use Wikimedia\TestingAccessWrapper;
-
-class LineFormatterTest extends MediaWikiTestCase {
-
- protected function setUp() {
- if ( !class_exists( 'Monolog\Formatter\LineFormatter' ) ) {
- $this->markTestSkipped( 'This test requires monolog to be installed' );
- }
- parent::setUp();
- }
-
- /**
- * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
- */
- public function testNormalizeExceptionNoTrace() {
- $fixture = new LineFormatter();
- $fixture->includeStacktraces( false );
- $fixture = TestingAccessWrapper::newFromObject( $fixture );
- $boom = new InvalidArgumentException( 'boom', 0,
- new LengthException( 'too long', 0,
- new LogicException( 'Spock wuz here' )
- )
- );
- $out = $fixture->normalizeException( $boom );
- $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
- $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
- $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
- $this->assertNotContains( "\n #0", $out );
- }
-
- /**
- * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
- */
- public function testNormalizeExceptionTrace() {
- $fixture = new LineFormatter();
- $fixture->includeStacktraces( true );
- $fixture = TestingAccessWrapper::newFromObject( $fixture );
- $boom = new InvalidArgumentException( 'boom', 0,
- new LengthException( 'too long', 0,
- new LogicException( 'Spock wuz here' )
- )
- );
- $out = $fixture->normalizeException( $boom );
- $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
- $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
- $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
- $this->assertContains( "\n #0", $out );
- }
-
- /**
- * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
- */
- public function testNormalizeExceptionErrorNoTrace() {
- if ( !class_exists( AssertionError::class ) ) {
- $this->markTestSkipped( 'AssertionError class does not exist' );
- }
-
- $fixture = new LineFormatter();
- $fixture->includeStacktraces( false );
- $fixture = TestingAccessWrapper::newFromObject( $fixture );
- $boom = new InvalidArgumentException( 'boom', 0,
- new LengthException( 'too long', 0,
- new AssertionError( 'Spock wuz here' )
- )
- );
- $out = $fixture->normalizeException( $boom );
- $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
- $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
- $this->assertContains( "\nCaused by: [Error AssertionError]", $out );
- $this->assertNotContains( "\n #0", $out );
- }
-
- /**
- * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
- */
- public function testNormalizeExceptionErrorTrace() {
- if ( !class_exists( AssertionError::class ) ) {
- $this->markTestSkipped( 'AssertionError class does not exist' );
- }
-
- $fixture = new LineFormatter();
- $fixture->includeStacktraces( true );
- $fixture = TestingAccessWrapper::newFromObject( $fixture );
- $boom = new InvalidArgumentException( 'boom', 0,
- new LengthException( 'too long', 0,
- new AssertionError( 'Spock wuz here' )
- )
- );
- $out = $fixture->normalizeException( $boom );
- $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
- $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
- $this->assertContains( "\nCaused by: [Error AssertionError]", $out );
- $this->assertContains( "\n #0", $out );
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @author Addshore
- *
- * @group Diff
- */
-class ArrayDiffFormatterTest extends MediaWikiTestCase {
-
- /**
- * @param Diff $input
- * @param array $expectedOutput
- * @dataProvider provideTestFormat
- * @covers ArrayDiffFormatter::format
- */
- public function testFormat( $input, $expectedOutput ) {
- $instance = new ArrayDiffFormatter();
- $output = $instance->format( $input );
- $this->assertEquals( $expectedOutput, $output );
- }
-
- private function getMockDiff( $edits ) {
- $diff = $this->getMockBuilder( Diff::class )
- ->disableOriginalConstructor()
- ->getMock();
- $diff->expects( $this->any() )
- ->method( 'getEdits' )
- ->will( $this->returnValue( $edits ) );
- return $diff;
- }
-
- private function getMockDiffOp( $type = null, $orig = [], $closing = [] ) {
- $diffOp = $this->getMockBuilder( DiffOp::class )
- ->disableOriginalConstructor()
- ->getMock();
- $diffOp->expects( $this->any() )
- ->method( 'getType' )
- ->will( $this->returnValue( $type ) );
- $diffOp->expects( $this->any() )
- ->method( 'getOrig' )
- ->will( $this->returnValue( $orig ) );
- if ( $type === 'change' ) {
- $diffOp->expects( $this->any() )
- ->method( 'getClosing' )
- ->with( $this->isType( 'integer' ) )
- ->will( $this->returnCallback( function () {
- return 'mockLine';
- } ) );
- } else {
- $diffOp->expects( $this->any() )
- ->method( 'getClosing' )
- ->will( $this->returnValue( $closing ) );
- }
- return $diffOp;
- }
-
- public function provideTestFormat() {
- $emptyArrayTestCases = [
- $this->getMockDiff( [] ),
- $this->getMockDiff( [ $this->getMockDiffOp( 'add' ) ] ),
- $this->getMockDiff( [ $this->getMockDiffOp( 'delete' ) ] ),
- $this->getMockDiff( [ $this->getMockDiffOp( 'change' ) ] ),
- $this->getMockDiff( [ $this->getMockDiffOp( 'copy' ) ] ),
- $this->getMockDiff( [ $this->getMockDiffOp( 'FOOBARBAZ' ) ] ),
- $this->getMockDiff( [ $this->getMockDiffOp( 'add', 'line' ) ] ),
- $this->getMockDiff( [ $this->getMockDiffOp( 'delete', [], [ 'line' ] ) ] ),
- $this->getMockDiff( [ $this->getMockDiffOp( 'copy', [], [ 'line' ] ) ] ),
- ];
-
- $otherTestCases = [];
- $otherTestCases[] = [
- $this->getMockDiff( [ $this->getMockDiffOp( 'add', [], [ 'a1' ] ) ] ),
- [ [ 'action' => 'add', 'new' => 'a1', 'newline' => 1 ] ],
- ];
- $otherTestCases[] = [
- $this->getMockDiff( [ $this->getMockDiffOp( 'add', [], [ 'a1', 'a2' ] ) ] ),
- [
- [ 'action' => 'add', 'new' => 'a1', 'newline' => 1 ],
- [ 'action' => 'add', 'new' => 'a2', 'newline' => 2 ],
- ],
- ];
- $otherTestCases[] = [
- $this->getMockDiff( [ $this->getMockDiffOp( 'delete', [ 'd1' ] ) ] ),
- [ [ 'action' => 'delete', 'old' => 'd1', 'oldline' => 1 ] ],
- ];
- $otherTestCases[] = [
- $this->getMockDiff( [ $this->getMockDiffOp( 'delete', [ 'd1', 'd2' ] ) ] ),
- [
- [ 'action' => 'delete', 'old' => 'd1', 'oldline' => 1 ],
- [ 'action' => 'delete', 'old' => 'd2', 'oldline' => 2 ],
- ],
- ];
- $otherTestCases[] = [
- $this->getMockDiff( [ $this->getMockDiffOp( 'change', [ 'd1' ], [ 'a1' ] ) ] ),
- [ [
- 'action' => 'change',
- 'old' => 'd1',
- 'new' => 'mockLine',
- 'newline' => 1, 'oldline' => 1
- ] ],
- ];
- $otherTestCases[] = [
- $this->getMockDiff( [ $this->getMockDiffOp(
- 'change',
- [ 'd1', 'd2' ],
- [ 'a1', 'a2' ]
- ) ] ),
- [
- [
- 'action' => 'change',
- 'old' => 'd1',
- 'new' => 'mockLine',
- 'newline' => 1, 'oldline' => 1
- ],
- [
- 'action' => 'change',
- 'old' => 'd2',
- 'new' => 'mockLine',
- 'newline' => 2, 'oldline' => 2
- ],
- ],
- ];
-
- $testCases = [];
- foreach ( $emptyArrayTestCases as $testCase ) {
- $testCases[] = [ $testCase, [] ];
- }
- foreach ( $otherTestCases as $testCase ) {
- $testCases[] = [ $testCase[0], $testCase[1] ];
- }
- return $testCases;
- }
-
-}
+++ /dev/null
-<?php
-/**
- * @author Addshore
- *
- * @group Diff
- */
-class DiffOpTest extends MediaWikiTestCase {
-
- /**
- * @covers DiffOp::getType
- */
- public function testGetType() {
- $obj = new FakeDiffOp();
- $obj->type = 'foo';
- $this->assertEquals( 'foo', $obj->getType() );
- }
-
- /**
- * @covers DiffOp::getOrig
- */
- public function testGetOrig() {
- $obj = new FakeDiffOp();
- $obj->orig = [ 'foo' ];
- $this->assertEquals( [ 'foo' ], $obj->getOrig() );
- }
-
- /**
- * @covers DiffOp::getClosing
- */
- public function testGetClosing() {
- $obj = new FakeDiffOp();
- $obj->closing = [ 'foo' ];
- $this->assertEquals( [ 'foo' ], $obj->getClosing() );
- }
-
- /**
- * @covers DiffOp::getClosing
- */
- public function testGetClosingWithParameter() {
- $obj = new FakeDiffOp();
- $obj->closing = [ 'foo', 'bar', 'baz' ];
- $this->assertEquals( 'foo', $obj->getClosing( 0 ) );
- $this->assertEquals( 'bar', $obj->getClosing( 1 ) );
- $this->assertEquals( 'baz', $obj->getClosing( 2 ) );
- $this->assertEquals( null, $obj->getClosing( 3 ) );
- }
-
- /**
- * @covers DiffOp::norig
- */
- public function testNorig() {
- $obj = new FakeDiffOp();
- $this->assertEquals( 0, $obj->norig() );
- $obj->orig = [ 'foo' ];
- $this->assertEquals( 1, $obj->norig() );
- }
-
- /**
- * @covers DiffOp::nclosing
- */
- public function testNclosing() {
- $obj = new FakeDiffOp();
- $this->assertEquals( 0, $obj->nclosing() );
- $obj->closing = [ 'foo' ];
- $this->assertEquals( 1, $obj->nclosing() );
- }
-
-}
+++ /dev/null
-<?php
-
-/**
- * @author Addshore
- *
- * @group Diff
- */
-class DiffTest extends MediaWikiTestCase {
-
- /**
- * @covers Diff::getEdits
- */
- public function testGetEdits() {
- $obj = new Diff( [], [] );
- $obj->edits = 'FooBarBaz';
- $this->assertEquals( 'FooBarBaz', $obj->getEdits() );
- }
-
-}
+++ /dev/null
-<?php
-/**
- * @author Antoine Musso
- * @copyright Copyright © 2013, Antoine Musso
- * @copyright Copyright © 2013, Wikimedia Foundation Inc.
- * @file
- */
-
-class MWExceptionHandlerTest extends MediaWikiTestCase {
-
- /**
- * @covers MWExceptionHandler::getRedactedTrace
- */
- public function testGetRedactedTrace() {
- $refvar = 'value';
- try {
- $array = [ 'a', 'b' ];
- $object = new stdClass();
- self::helperThrowAnException( $array, $object, $refvar );
- } catch ( Exception $e ) {
- }
-
- # Make sure our stack trace contains an array and an object passed to
- # some function in the stacktrace. Else, we can not assert the trace
- # redaction achieved its job.
- $trace = $e->getTrace();
- $hasObject = false;
- $hasArray = false;
- foreach ( $trace as $frame ) {
- if ( !isset( $frame['args'] ) ) {
- continue;
- }
- foreach ( $frame['args'] as $arg ) {
- $hasObject = $hasObject || is_object( $arg );
- $hasArray = $hasArray || is_array( $arg );
- }
-
- if ( $hasObject && $hasArray ) {
- break;
- }
- }
- $this->assertTrue( $hasObject,
- "The stacktrace must have a function having an object has parameter" );
- $this->assertTrue( $hasArray,
- "The stacktrace must have a function having an array has parameter" );
-
- # Now we redact the trace.. and make sure no function arguments are
- # arrays or objects.
- $redacted = MWExceptionHandler::getRedactedTrace( $e );
-
- foreach ( $redacted as $frame ) {
- if ( !isset( $frame['args'] ) ) {
- continue;
- }
- foreach ( $frame['args'] as $arg ) {
- $this->assertNotInternalType( 'array', $arg );
- $this->assertNotInternalType( 'object', $arg );
- }
- }
-
- $this->assertEquals( 'value', $refvar, 'Ensuring reference variable wasn\'t changed' );
- }
-
- /**
- * Helper function for testExpandArgumentsInCall
- *
- * Pass it an object and an array, and something by reference :-)
- *
- * @throws Exception
- */
- protected static function helperThrowAnException( $a, $b, &$c ) {
- throw new Exception();
- }
-}
+++ /dev/null
-<?php
-
-class InstallDocFormatterTest extends MediaWikiTestCase {
- /**
- * @covers InstallDocFormatter
- * @dataProvider provideDocFormattingTests
- */
- public function testFormat( $expected, $unformattedText, $message = '' ) {
- $this->assertEquals(
- $expected,
- InstallDocFormatter::format( $unformattedText ),
- $message
- );
- }
-
- /**
- * Provider for testFormat()
- */
- public static function provideDocFormattingTests() {
- # Format: (expected string, unformattedText string, optional message)
- return [
- # Escape some wikitext
- [ 'Install <tag>', 'Install <tag>', 'Escaping <' ],
- [ 'Install {{template}}', 'Install {{template}}', 'Escaping [[' ],
- [ 'Install [[page]]', 'Install [[page]]', 'Escaping {{' ],
- [ 'Install __TOC__', 'Install __TOC__', 'Escaping __' ],
- [ 'Install ', "Install \r", 'Removing \r' ],
-
- # Transform \t{1,2} into :{1,2}
- [ ':One indentation', "\tOne indentation", 'Replacing a single \t' ],
- [ '::Two indentations', "\t\tTwo indentations", 'Replacing 2 x \t' ],
-
- # Transform 'T123' links
- [
- '<span class="config-plainlink">[https://phabricator.wikimedia.org/T123 T123]</span>',
- 'T123', 'Testing T123 links' ],
- [
- 'bug <span class="config-plainlink">[https://phabricator.wikimedia.org/T123 T123]</span>',
- 'bug T123', 'Testing bug T123 links' ],
- [
- '(<span class="config-plainlink">[https://phabricator.wikimedia.org/T987654 T987654]</span>)',
- '(T987654)', 'Testing (T987654) links' ],
-
- # "Tabc" shouldn't work
- [ 'Tfoobar', 'Tfoobar', "Don't match T followed by non-digits" ],
- [ 'T!!fakefake!!', 'T!!fakefake!!', "Don't match T followed by non-digits" ],
-
- # Transform 'bug 123' links
- [
- '<span class="config-plainlink">[https://bugzilla.wikimedia.org/123 bug 123]</span>',
- 'bug 123', 'Testing bug 123 links' ],
- [
- '(<span class="config-plainlink">[https://bugzilla.wikimedia.org/987654 bug 987654]</span>)',
- '(bug 987654)', 'Testing (bug 987654) links' ],
-
- # "bug abc" shouldn't work
- [ 'bug foobar', 'bug foobar', "Don't match bug followed by non-digits" ],
- [ 'bug !!fakefake!!', 'bug !!fakefake!!', "Don't match bug followed by non-digits" ],
-
- # Transform '$wgFooBar' links
- [
- '<span class="config-plainlink">'
- . '[https://www.mediawiki.org/wiki/Manual:$wgFooBar $wgFooBar]</span>',
- '$wgFooBar', 'Testing basic $wgFooBar' ],
- [
- '<span class="config-plainlink">'
- . '[https://www.mediawiki.org/wiki/Manual:$wgFooBar45 $wgFooBar45]</span>',
- '$wgFooBar45', 'Testing $wgFooBar45 (with numbers)' ],
- [
- '<span class="config-plainlink">'
- . '[https://www.mediawiki.org/wiki/Manual:$wgFoo_Bar $wgFoo_Bar]</span>',
- '$wgFoo_Bar', 'Testing $wgFoo_Bar (with underscore)' ],
-
- # Icky variables that shouldn't link
- [
- '$myAwesomeVariable',
- '$myAwesomeVariable',
- 'Testing $myAwesomeVariable (not starting with $wg)'
- ],
- [ '$()not!a&Var', '$()not!a&Var', 'Testing $()not!a&Var (obviously not a variable)' ],
- ];
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @group Database
- * @group Installer
- */
-class OracleInstallerTest extends MediaWikiTestCase {
-
- /**
- * @dataProvider provideOracleConnectStrings
- * @covers OracleInstaller::checkConnectStringFormat
- */
- public function testCheckConnectStringFormat( $expected, $connectString, $msg = '' ) {
- $validity = $expected ? 'should be valid' : 'should NOT be valid';
- $msg = "'$connectString' ($msg) $validity.";
- $this->assertEquals( $expected,
- OracleInstaller::checkConnectStringFormat( $connectString ),
- $msg
- );
- }
-
- /**
- * Provider to test OracleInstaller::checkConnectStringFormat()
- */
- function provideOracleConnectStrings() {
- // expected result, connectString[, message]
- return [
- [ true, 'simple_01', 'Simple TNS name' ],
- [ true, 'simple_01.world', 'TNS name with domain' ],
- [ true, 'simple_01.domain.net', 'TNS name with domain' ],
- [ true, 'host123', 'Host only' ],
- [ true, 'host123.domain.net', 'FQDN only' ],
- [ true, '//host123.domain.net', 'FQDN URL only' ],
- [ true, '123.223.213.132', 'Host IP only' ],
- [ true, 'host:1521', 'Host and port' ],
- [ true, 'host:1521/service', 'Host, port and service' ],
- [ true, 'host:1521/service:shared', 'Host, port, service and shared server type' ],
- [ true, 'host:1521/service:dedicated', 'Host, port, service and dedicated server type' ],
- [ true, 'host:1521/service:pooled', 'Host, port, service and pooled server type' ],
- [
- true,
- 'host:1521/service:shared/instance1',
- 'Host, port, service, server type and instance'
- ],
- [ true, 'host:1521//instance1', 'Host, port and instance' ],
- ];
- }
-
-}
+++ /dev/null
-<?php
-
-use MediaWiki\Interwiki\InterwikiLookupAdapter;
-
-/**
- * @covers MediaWiki\Interwiki\InterwikiLookupAdapter
- *
- * @group MediaWiki
- * @group Interwiki
- */
-class InterwikiLookupAdapterTest extends MediaWikiTestCase {
-
- /**
- * @var InterwikiLookupAdapter
- */
- private $interwikiLookup;
-
- protected function setUp() {
- parent::setUp();
-
- $this->interwikiLookup = new InterwikiLookupAdapter(
- $this->getSiteLookup( $this->getSites() )
- );
- }
-
- public function testIsValidInterwiki() {
- $this->assertTrue(
- $this->interwikiLookup->isValidInterwiki( 'enwt' ),
- 'enwt known prefix is valid'
- );
- $this->assertTrue(
- $this->interwikiLookup->isValidInterwiki( 'foo' ),
- 'foo site known prefix is valid'
- );
- $this->assertFalse(
- $this->interwikiLookup->isValidInterwiki( 'xyz' ),
- 'unknown prefix is not valid'
- );
- }
-
- public function testFetch() {
- $interwiki = $this->interwikiLookup->fetch( '' );
- $this->assertNull( $interwiki );
-
- $interwiki = $this->interwikiLookup->fetch( 'xyz' );
- $this->assertFalse( $interwiki );
-
- $interwiki = $this->interwikiLookup->fetch( 'foo' );
- $this->assertInstanceOf( Interwiki::class, $interwiki );
- $this->assertSame( 'foobar', $interwiki->getWikiID() );
-
- $interwiki = $this->interwikiLookup->fetch( 'enwt' );
- $this->assertInstanceOf( Interwiki::class, $interwiki );
-
- $this->assertSame( 'https://en.wiktionary.org/wiki/$1', $interwiki->getURL(), 'getURL' );
- $this->assertSame( 'https://en.wiktionary.org/w/api.php', $interwiki->getAPI(), 'getAPI' );
- $this->assertSame( 'enwiktionary', $interwiki->getWikiID(), 'getWikiID' );
- $this->assertTrue( $interwiki->isLocal(), 'isLocal' );
- }
-
- public function testGetAllPrefixes() {
- $foo = [
- 'iw_prefix' => 'foo',
- 'iw_url' => '',
- 'iw_api' => '',
- 'iw_wikiid' => 'foobar',
- 'iw_local' => false,
- 'iw_trans' => false,
- ];
- $enwt = [
- 'iw_prefix' => 'enwt',
- 'iw_url' => 'https://en.wiktionary.org/wiki/$1',
- 'iw_api' => 'https://en.wiktionary.org/w/api.php',
- 'iw_wikiid' => 'enwiktionary',
- 'iw_local' => true,
- 'iw_trans' => false,
- ];
-
- $this->assertEquals(
- [ $foo, $enwt ],
- $this->interwikiLookup->getAllPrefixes(),
- 'getAllPrefixes()'
- );
-
- $this->assertEquals(
- [ $foo ],
- $this->interwikiLookup->getAllPrefixes( false ),
- 'get external prefixes'
- );
-
- $this->assertEquals(
- [ $enwt ],
- $this->interwikiLookup->getAllPrefixes( true ),
- 'get local prefixes'
- );
- }
-
- private function getSiteLookup( SiteList $sites ) {
- $siteLookup = $this->getMockBuilder( SiteLookup::class )
- ->disableOriginalConstructor()
- ->getMock();
-
- $siteLookup->expects( $this->any() )
- ->method( 'getSites' )
- ->will( $this->returnValue( $sites ) );
-
- return $siteLookup;
- }
-
- private function getSites() {
- $sites = [];
-
- $site = new Site();
- $site->setGlobalId( 'foobar' );
- $site->addInterwikiId( 'foo' );
- $site->setSource( 'external' );
- $sites[] = $site;
-
- $site = new MediaWikiSite();
- $site->setGlobalId( 'enwiktionary' );
- $site->setGroup( 'wiktionary' );
- $site->setLanguageCode( 'en' );
- $site->addNavigationId( 'enwiktionary' );
- $site->addInterwikiId( 'enwt' );
- $site->setSource( 'local' );
- $site->setPath( MediaWikiSite::PATH_PAGE, "https://en.wiktionary.org/wiki/$1" );
- $site->setPath( MediaWikiSite::PATH_FILE, "https://en.wiktionary.org/w/$1" );
- $sites[] = $site;
-
- return new SiteList( $sites );
- }
-
-}
+++ /dev/null
-<?php
-
-class ReplicatedBagOStuffTest extends MediaWikiTestCase {
- /** @var HashBagOStuff */
- private $writeCache;
- /** @var HashBagOStuff */
- private $readCache;
- /** @var ReplicatedBagOStuff */
- private $cache;
-
- protected function setUp() {
- parent::setUp();
-
- $this->writeCache = new HashBagOStuff();
- $this->readCache = new HashBagOStuff();
- $this->cache = new ReplicatedBagOStuff( [
- 'writeFactory' => $this->writeCache,
- 'readFactory' => $this->readCache,
- ] );
- }
-
- /**
- * @covers ReplicatedBagOStuff::set
- */
- public function testSet() {
- $key = 'a key';
- $value = 'a value';
- $this->cache->set( $key, $value );
-
- // Write to master.
- $this->assertEquals( $value, $this->writeCache->get( $key ) );
- // Don't write to replica. Replication is deferred to backend.
- $this->assertFalse( $this->readCache->get( $key ) );
- }
-
- /**
- * @covers ReplicatedBagOStuff::get
- */
- public function testGet() {
- $key = 'a key';
-
- $write = 'one value';
- $this->writeCache->set( $key, $write );
- $read = 'another value';
- $this->readCache->set( $key, $read );
-
- // Read from replica.
- $this->assertEquals( $read, $this->cache->get( $key ) );
- }
-
- /**
- * @covers ReplicatedBagOStuff::get
- */
- public function testGetAbsent() {
- $key = 'a key';
- $value = 'a value';
- $this->writeCache->set( $key, $value );
-
- // Don't read from master. No failover if value is absent.
- $this->assertFalse( $this->cache->get( $key ) );
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @group Media
- */
-class IPTCTest extends MediaWikiTestCase {
-
- /**
- * @covers IPTC::getCharset
- */
- public function testRecognizeUtf8() {
- // utf-8 is the only one used in practise.
- $res = IPTC::getCharset( "\x1b%G" );
- $this->assertEquals( 'UTF-8', $res );
- }
-
- /**
- * @covers IPTC::parse
- */
- public function testIPTCParseNoCharset88591() {
- // basically IPTC for keyword with value of 0xBC which is 1/4 in iso-8859-1
- // This data doesn't specify a charset. We're supposed to guess
- // (which basically means utf-8 if valid, windows 1252 (iso 8859-1) if not)
- $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x06\x1c\x02\x19\x00\x01\xBC";
- $res = IPTC::parse( $iptcData );
- $this->assertEquals( [ '¼' ], $res['Keywords'] );
- }
-
- /**
- * @covers IPTC::parse
- */
- public function testIPTCParseNoCharset88591b() {
- /* This one contains a sequence that's valid iso 8859-1 but not valid utf8 */
- /* \xC3 = Ã, \xB8 = ¸ */
- $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x09\x1c\x02\x19\x00\x04\xC3\xC3\xC3\xB8";
- $res = IPTC::parse( $iptcData );
- $this->assertEquals( [ 'ÃÃø' ], $res['Keywords'] );
- }
-
- /**
- * Same as testIPTCParseNoCharset88591b, but forcing the charset to utf-8.
- * What should happen is the first "\xC3\xC3" should be dropped as invalid,
- * leaving \xC3\xB8, which is ø
- * @covers IPTC::parse
- */
- public function testIPTCParseForcedUTFButInvalid() {
- $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x11\x1c\x02\x19\x00\x04\xC3\xC3\xC3\xB8"
- . "\x1c\x01\x5A\x00\x03\x1B\x25\x47";
- $res = IPTC::parse( $iptcData );
- $this->assertEquals( [ 'ø' ], $res['Keywords'] );
- }
-
- /**
- * @covers IPTC::parse
- */
- public function testIPTCParseNoCharsetUTF8() {
- $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x07\x1c\x02\x19\x00\x02¼";
- $res = IPTC::parse( $iptcData );
- $this->assertEquals( [ '¼' ], $res['Keywords'] );
- }
-
- /**
- * Testing something that has 2 values for keyword
- * @covers IPTC::parse
- */
- public function testIPTCParseMulti() {
- $iptcData = /* identifier */ "Photoshop 3.0\08BIM\4\4"
- /* length */ . "\0\0\0\0\0\x0D"
- . "\x1c\x02\x19" . "\x00\x01" . "\xBC"
- . "\x1c\x02\x19" . "\x00\x02" . "\xBC\xBD";
- $res = IPTC::parse( $iptcData );
- $this->assertEquals( [ '¼', '¼½' ], $res['Keywords'] );
- }
-
- /**
- * @covers IPTC::parse
- */
- public function testIPTCParseUTF8() {
- // This has the magic "\x1c\x01\x5A\x00\x03\x1B\x25\x47" which marks content as UTF8.
- $iptcData =
- "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x0F\x1c\x02\x19\x00\x02¼\x1c\x01\x5A\x00\x03\x1B\x25\x47";
- $res = IPTC::parse( $iptcData );
- $this->assertEquals( [ '¼' ], $res['Keywords'] );
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @group Media
- */
-class MediaHandlerTest extends MediaWikiTestCase {
-
- /**
- * @covers MediaHandler::fitBoxWidth
- *
- * @dataProvider provideTestFitBoxWidth
- */
- public function testFitBoxWidth( $width, $height, $max, $expected ) {
- $y = round( $expected * $height / $width );
- $result = MediaHandler::fitBoxWidth( $width, $height, $max );
- $y2 = round( $result * $height / $width );
- $this->assertEquals( $expected,
- $result,
- "($width, $height, $max) wanted: {$expected}x$y, got: {z$result}x$y2" );
- }
-
- public static function provideTestFitBoxWidth() {
- return array_merge(
- static::generateTestFitBoxWidthData( 50, 50, [
- 50 => 50,
- 17 => 17,
- 18 => 18 ]
- ),
- static::generateTestFitBoxWidthData( 366, 300, [
- 50 => 61,
- 17 => 21,
- 18 => 22 ]
- ),
- static::generateTestFitBoxWidthData( 300, 366, [
- 50 => 41,
- 17 => 14,
- 18 => 15 ]
- ),
- static::generateTestFitBoxWidthData( 100, 400, [
- 50 => 12,
- 17 => 4,
- 18 => 4 ]
- )
- );
- }
-
- /**
- * Generate single test cases by combining the dimensions and tests contents
- *
- * It creates:
- * [$width, $height, $max, $expected],
- * [$width, $height, $max2, $expected2], ...
- * out of parameters:
- * $width, $height, { $max => $expected, $max2 => $expected2, ... }
- *
- * @param int $width
- * @param int $height
- * @param array $tests associative array of $max => $expected values
- * @return array
- */
- private static function generateTestFitBoxWidthData( $width, $height, $tests ) {
- $result = [];
- foreach ( $tests as $max => $expected ) {
- $result[] = [ $width, $height, $max, $expected ];
- }
- return $result;
- }
-}
+++ /dev/null
-<?php
-/**
- * @group BagOStuff
- */
-class MemcachedBagOStuffTest extends MediaWikiTestCase {
- /** @var MemcachedBagOStuff */
- private $cache;
-
- protected function setUp() {
- parent::setUp();
- $this->cache = new MemcachedPhpBagOStuff( [ 'keyspace' => 'test', 'servers' => [] ] );
- }
-
- /**
- * @covers MemcachedBagOStuff::makeKey
- */
- public function testKeyNormalization() {
- $this->assertEquals(
- 'test:vanilla',
- $this->cache->makeKey( 'vanilla' )
- );
-
- $this->assertEquals(
- 'test:punctuation_marks_are_ok:!@$^&*()',
- $this->cache->makeKey( 'punctuation_marks_are_ok', '!@$^&*()' )
- );
-
- $this->assertEquals(
- 'test:but_spaces:hashes%23:and%0Anewlines:are_not',
- $this->cache->makeKey( 'but spaces', 'hashes#', "and\nnewlines", 'are_not' )
- );
-
- $this->assertEquals(
- 'test:this:key:contains:%F0%9D%95%9E%F0%9D%95%A6%F0%9D%95%9D%F0%9D%95%A5%F0%9' .
- 'D%95%9A%F0%9D%95%93%F0%9D%95%AA%F0%9D%95%A5%F0%9D%95%96:characters',
- $this->cache->makeKey( 'this', 'key', 'contains', '𝕞𝕦𝕝𝕥𝕚𝕓𝕪𝕥𝕖', 'characters' )
- );
-
- $this->assertEquals(
- 'test:this:key:contains:#c118f92685a635cb843039de50014c9c',
- $this->cache->makeKey( 'this', 'key', 'contains', '𝕥𝕠𝕠 𝕞𝕒𝕟𝕪 𝕞𝕦𝕝𝕥𝕚𝕓𝕪𝕥𝕖 𝕔𝕙𝕒𝕣𝕒𝕔𝕥𝕖𝕣𝕤' )
- );
-
- $this->assertEquals(
- 'test:BagOStuff-long-key:##dc89dcb43b28614da27660240af478b5',
- $this->cache->makeKey( '𝕖𝕧𝕖𝕟', '𝕚𝕗', '𝕨𝕖', '𝕄𝔻𝟝', '𝕖𝕒𝕔𝕙',
- '𝕒𝕣𝕘𝕦𝕞𝕖𝕟𝕥', '𝕥𝕙𝕚𝕤', '𝕜𝕖𝕪', '𝕨𝕠𝕦𝕝𝕕', '𝕤𝕥𝕚𝕝𝕝', '𝕓𝕖', '𝕥𝕠𝕠', '𝕝𝕠𝕟𝕘' )
- );
-
- $this->assertEquals(
- 'test:%23%235820ad1d105aa4dc698585c39df73e19',
- $this->cache->makeKey( '##5820ad1d105aa4dc698585c39df73e19' )
- );
-
- $this->assertEquals(
- 'test:percent_is_escaped:!@$%25^&*()',
- $this->cache->makeKey( 'percent_is_escaped', '!@$%^&*()' )
- );
-
- $this->assertEquals(
- 'test:colon_is_escaped:!@$%3A^&*()',
- $this->cache->makeKey( 'colon_is_escaped', '!@$:^&*()' )
- );
-
- $this->assertEquals(
- 'test:long_key_part_hashed:#0244f7b1811d982dd932dd7de01465ac',
- $this->cache->makeKey( 'long_key_part_hashed', str_repeat( 'y', 500 ) )
- );
- }
-
- /**
- * @dataProvider validKeyProvider
- * @covers MemcachedBagOStuff::validateKeyEncoding
- */
- public function testValidateKeyEncoding( $key ) {
- $this->assertSame( $key, $this->cache->validateKeyEncoding( $key ) );
- }
-
- public function validKeyProvider() {
- return [
- 'empty' => [ '' ],
- 'digits' => [ '09' ],
- 'letters' => [ 'AZaz' ],
- 'ASCII special characters' => [ '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' ],
- ];
- }
-
- /**
- * @dataProvider invalidKeyProvider
- * @covers MemcachedBagOStuff::validateKeyEncoding
- */
- public function testValidateKeyEncodingThrowsException( $key ) {
- $this->setExpectedException( Exception::class );
- $this->cache->validateKeyEncoding( $key );
- }
-
- public function invalidKeyProvider() {
- return [
- [ "\x00" ],
- [ ' ' ],
- [ "\x1F" ],
- [ "\x7F" ],
- [ "\x80" ],
- [ "\xFF" ],
- ];
- }
-}
+++ /dev/null
-<?php
-/**
- * @group BagOStuff
- *
- * @covers RESTBagOStuff
- */
-class RESTBagOStuffTest extends MediaWikiTestCase {
-
- /**
- * @var MultiHttpClient
- */
- private $client;
- /**
- * @var RESTBagOStuff
- */
- private $bag;
-
- public function setUp() {
- parent::setUp();
- $this->client =
- $this->getMockBuilder( MultiHttpClient::class )
- ->setConstructorArgs( [ [] ] )
- ->setMethods( [ 'run' ] )
- ->getMock();
- $this->bag = new RESTBagOStuff( [ 'client' => $this->client, 'url' => 'http://test/rest/' ] );
- }
-
- public function testGet() {
- $this->client->expects( $this->once() )->method( 'run' )->with( [
- 'method' => 'GET',
- 'url' => 'http://test/rest/42xyz42',
- 'headers' => []
- // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
- ] )->willReturn( [ 200, 'OK', [], '"somedata"', 0 ] );
- $result = $this->bag->get( '42xyz42' );
- $this->assertEquals( 'somedata', $result );
- }
-
- public function testGetNotExist() {
- $this->client->expects( $this->once() )->method( 'run' )->with( [
- 'method' => 'GET',
- 'url' => 'http://test/rest/42xyz42',
- 'headers' => []
- // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
- ] )->willReturn( [ 404, 'Not found', [], 'Nothing to see here', 0 ] );
- $result = $this->bag->get( '42xyz42' );
- $this->assertFalse( $result );
- }
-
- public function testGetBadClient() {
- $this->client->expects( $this->once() )->method( 'run' )->with( [
- 'method' => 'GET',
- 'url' => 'http://test/rest/42xyz42',
- 'headers' => []
- // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
- ] )->willReturn( [ 0, '', [], '', 'cURL has failed you today' ] );
- $result = $this->bag->get( '42xyz42' );
- $this->assertFalse( $result );
- $this->assertEquals( BagOStuff::ERR_UNREACHABLE, $this->bag->getLastError() );
- }
-
- public function testGetBadServer() {
- $this->client->expects( $this->once() )->method( 'run' )->with( [
- 'method' => 'GET',
- 'url' => 'http://test/rest/42xyz42',
- 'headers' => []
- // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
- ] )->willReturn( [ 500, 'Too busy', [], 'Server is too busy', '' ] );
- $result = $this->bag->get( '42xyz42' );
- $this->assertFalse( $result );
- $this->assertEquals( BagOStuff::ERR_UNEXPECTED, $this->bag->getLastError() );
- }
-
- public function testPut() {
- $this->client->expects( $this->once() )->method( 'run' )->with( [
- 'method' => 'PUT',
- 'url' => 'http://test/rest/42xyz42',
- 'body' => '"postdata"',
- 'headers' => []
- // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
- ] )->willReturn( [ 200, 'OK', [], 'Done', 0 ] );
- $result = $this->bag->set( '42xyz42', 'postdata' );
- $this->assertTrue( $result );
- }
-
- public function testDelete() {
- $this->client->expects( $this->once() )->method( 'run' )->with( [
- 'method' => 'DELETE',
- 'url' => 'http://test/rest/42xyz42',
- 'headers' => []
- // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
- ] )->willReturn( [ 200, 'OK', [], 'Done', 0 ] );
- $result = $this->bag->delete( '42xyz42' );
- $this->assertTrue( $result );
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @group Parser
- * @covers MWTidy
- */
-class TidyTest extends MediaWikiTestCase {
-
- protected function setUp() {
- parent::setUp();
- if ( !MWTidy::isEnabled() ) {
- $this->markTestSkipped( 'Tidy not found' );
- }
- }
-
- /**
- * @dataProvider provideTestWrapping
- */
- public function testTidyWrapping( $expected, $text, $msg = '' ) {
- $text = MWTidy::tidy( $text );
- // We don't care about where Tidy wants to stick is <p>s
- $text = trim( preg_replace( '#</?p>#', '', $text ) );
- // Windows, we love you!
- $text = str_replace( "\r", '', $text );
- $this->assertEquals( $expected, $text, $msg );
- }
-
- public static function provideTestWrapping() {
- $testMathML = <<<'MathML'
-<math xmlns="http://www.w3.org/1998/Math/MathML">
- <mrow>
- <mi>a</mi>
- <mo>⁢</mo>
- <msup>
- <mi>x</mi>
- <mn>2</mn>
- </msup>
- <mo>+</mo>
- <mi>b</mi>
- <mo>⁢ </mo>
- <mi>x</mi>
- <mo>+</mo>
- <mi>c</mi>
- </mrow>
- </math>
-MathML;
- return [
- [
- '<mw:editsection page="foo" section="bar">foo</mw:editsection>',
- '<mw:editsection page="foo" section="bar">foo</mw:editsection>',
- '<mw:editsection> should survive tidy'
- ],
- [
- '<editsection page="foo" section="bar">foo</editsection>',
- '<editsection page="foo" section="bar">foo</editsection>',
- '<editsection> should survive tidy'
- ],
- [ '<mw:toc>foo</mw:toc>', '<mw:toc>foo</mw:toc>', '<mw:toc> should survive tidy' ],
- [ "<link foo=\"bar\" />foo", '<link foo="bar"/>foo', '<link> should survive tidy' ],
- [ "<meta foo=\"bar\" />foo", '<meta foo="bar"/>foo', '<meta> should survive tidy' ],
- [ $testMathML, $testMathML, '<math> should survive tidy' ],
- ];
- }
-}
+++ /dev/null
-<?php
-/**
- * Testing framework for the Password infrastructure
- *
- * 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
- */
-
-/**
- * @covers InvalidPassword
- */
-class PasswordTest extends MediaWikiTestCase {
- public function testInvalidPlaintext() {
- $passwordFactory = new PasswordFactory();
- $invalid = $passwordFactory->newFromPlaintext( null );
-
- $this->assertInstanceOf( InvalidPassword::class, $invalid );
- }
-}
+++ /dev/null
-<?php
-/**
- * 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
- */
-
-use MediaWiki\Preferences\IntvalFilter;
-use MediaWiki\Preferences\MultiUsernameFilter;
-use MediaWiki\Preferences\TimezoneFilter;
-
-/**
- * @group Preferences
- */
-class FiltersTest extends MediaWikiTestCase {
- /**
- * @covers MediaWiki\Preferences\IntvalFilter::filterFromForm()
- * @covers MediaWiki\Preferences\IntvalFilter::filterForForm()
- */
- public function testIntvalFilter() {
- $filter = new IntvalFilter();
- self::assertSame( 0, $filter->filterFromForm( '0' ) );
- self::assertSame( 3, $filter->filterFromForm( '3' ) );
- self::assertSame( '123', $filter->filterForForm( '123' ) );
- }
-
- /**
- * @covers MediaWiki\Preferences\TimezoneFilter::filterFromForm()
- * @dataProvider provideTimezoneFilter
- *
- * @param string $input
- * @param string $expected
- */
- public function testTimezoneFilter( $input, $expected ) {
- $filter = new TimezoneFilter();
- $result = $filter->filterFromForm( $input );
- self::assertEquals( $expected, $result );
- }
-
- public function provideTimezoneFilter() {
- return [
- [ 'ZoneInfo', 'Offset|0' ],
- [ 'ZoneInfo|bogus', 'Offset|0' ],
- [ 'System', 'System' ],
- [ '2:30', 'Offset|150' ],
- ];
- }
-
- /**
- * @covers MediaWiki\Preferences\MultiUsernameFilter::filterFromForm()
- * @dataProvider provideMultiUsernameFilterFrom
- *
- * @param string $input
- * @param string|null $expected
- */
- public function testMultiUsernameFilterFrom( $input, $expected ) {
- $filter = $this->makeMultiUsernameFilter();
- $result = $filter->filterFromForm( $input );
- self::assertSame( $expected, $result );
- }
-
- public function provideMultiUsernameFilterFrom() {
- return [
- [ '', null ],
- [ "\n\n\n", null ],
- [ 'Foo', '1' ],
- [ "\n\n\nFoo\nBar\n", "1\n2" ],
- [ "Baz\nInvalid\nFoo", "3\n1" ],
- [ "Invalid", null ],
- [ "Invalid\n\n\nInvalid\n", null ],
- ];
- }
-
- /**
- * @covers MediaWiki\Preferences\MultiUsernameFilter::filterForForm()
- * @dataProvider provideMultiUsernameFilterFor
- *
- * @param string $input
- * @param string $expected
- */
- public function testMultiUsernameFilterFor( $input, $expected ) {
- $filter = $this->makeMultiUsernameFilter();
- $result = $filter->filterForForm( $input );
- self::assertSame( $expected, $result );
- }
-
- public function provideMultiUsernameFilterFor() {
- return [
- [ '', '' ],
- [ "\n", '' ],
- [ '1', 'Foo' ],
- [ "\n1\n\n2\377\n", "Foo\nBar" ],
- [ "666\n667", '' ],
- ];
- }
-
- private function makeMultiUsernameFilter() {
- $userMapping = [
- 'Foo' => 1,
- 'Bar' => 2,
- 'Baz' => 3,
- ];
- $flipped = array_flip( $userMapping );
- $idLookup = self::getMockBuilder( CentralIdLookup::class )
- ->disableOriginalConstructor()
- ->setMethods( [ 'centralIdsFromNames', 'namesFromCentralIds' ] )
- ->getMockForAbstractClass();
-
- $idLookup->method( 'centralIdsFromNames' )
- ->will( self::returnCallback( function ( $names ) use ( $userMapping ) {
- $ids = [];
- foreach ( $names as $name ) {
- $ids[] = $userMapping[$name] ?? null;
- }
- return array_filter( $ids, 'is_numeric' );
- } ) );
- $idLookup->method( 'namesFromCentralIds' )
- ->will( self::returnCallback( function ( $ids ) use ( $flipped ) {
- $names = [];
- foreach ( $ids as $id ) {
- $names[] = $flipped[$id] ?? null;
- }
- return array_filter( $names, 'is_string' );
- } ) );
-
- return new MultiUsernameFilter( $idLookup );
- }
-}
+++ /dev/null
-<?php
-
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * @covers ExtensionProcessor
- */
-class ExtensionProcessorTest extends MediaWikiTestCase {
-
- private $dir, $dirname;
-
- public function setUp() {
- parent::setUp();
- $this->dir = __DIR__ . '/FooBar/extension.json';
- $this->dirname = dirname( $this->dir );
- }
-
- /**
- * 'name' is absolutely required
- *
- * @var array
- */
- public static $default = [
- 'name' => 'FooBar',
- ];
-
- public function testExtractInfo() {
- // Test that attributes that begin with @ are ignored
- $processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, self::$default + [
- '@metadata' => [ 'foobarbaz' ],
- 'AnAttribute' => [ 'omg' ],
- 'AutoloadClasses' => [ 'FooBar' => 'includes/FooBar.php' ],
- 'SpecialPages' => [ 'Foo' => 'SpecialFoo' ],
- 'callback' => 'FooBar::onRegistration',
- ], 1 );
-
- $extracted = $processor->getExtractedInfo();
- $attributes = $extracted['attributes'];
- $this->assertArrayHasKey( 'AnAttribute', $attributes );
- $this->assertArrayNotHasKey( '@metadata', $attributes );
- $this->assertArrayNotHasKey( 'AutoloadClasses', $attributes );
- $this->assertSame(
- [ 'FooBar' => 'FooBar::onRegistration' ],
- $extracted['callbacks']
- );
- $this->assertSame(
- [ 'Foo' => 'SpecialFoo' ],
- $extracted['globals']['wgSpecialPages']
- );
- }
-
- public function testExtractNamespaces() {
- // Test that namespace IDs can be overwritten
- if ( !defined( 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X' ) ) {
- define( 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X', 123456 );
- }
-
- $processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, self::$default + [
- 'namespaces' => [
- [
- 'id' => 332200,
- 'constant' => 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A',
- 'name' => 'Test_A',
- 'defaultcontentmodel' => 'TestModel',
- 'gender' => [
- 'male' => 'Male test',
- 'female' => 'Female test',
- ],
- 'subpages' => true,
- 'content' => true,
- 'protection' => 'userright',
- ],
- [ // Test_X will use ID 123456 not 334400
- 'id' => 334400,
- 'constant' => 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X',
- 'name' => 'Test_X',
- 'defaultcontentmodel' => 'TestModel'
- ],
- ]
- ], 1 );
-
- $extracted = $processor->getExtractedInfo();
-
- $this->assertArrayHasKey(
- 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A',
- $extracted['defines']
- );
- $this->assertArrayNotHasKey(
- 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X',
- $extracted['defines']
- );
-
- $this->assertSame(
- $extracted['defines']['MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A'],
- 332200
- );
-
- $this->assertArrayHasKey( 'ExtensionNamespaces', $extracted['attributes'] );
- $this->assertArrayHasKey( 123456, $extracted['attributes']['ExtensionNamespaces'] );
- $this->assertArrayHasKey( 332200, $extracted['attributes']['ExtensionNamespaces'] );
- $this->assertArrayNotHasKey( 334400, $extracted['attributes']['ExtensionNamespaces'] );
-
- $this->assertSame( 'Test_X', $extracted['attributes']['ExtensionNamespaces'][123456] );
- $this->assertSame( 'Test_A', $extracted['attributes']['ExtensionNamespaces'][332200] );
- $this->assertSame(
- [ 'male' => 'Male test', 'female' => 'Female test' ],
- $extracted['globals']['wgExtraGenderNamespaces'][332200]
- );
- // A has subpages, X does not
- $this->assertTrue( $extracted['globals']['wgNamespacesWithSubpages'][332200] );
- $this->assertArrayNotHasKey( 123456, $extracted['globals']['wgNamespacesWithSubpages'] );
- }
-
- public static function provideRegisterHooks() {
- $merge = [ ExtensionRegistry::MERGE_STRATEGY => 'array_merge_recursive' ];
- // Format:
- // Current $wgHooks
- // Content in extension.json
- // Expected value of $wgHooks
- return [
- // No hooks
- [
- [],
- self::$default,
- $merge,
- ],
- // No current hooks, adding one for "FooBaz" in string format
- [
- [],
- [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
- [ 'FooBaz' => [ 'FooBazCallback' ] ] + $merge,
- ],
- // Hook for "FooBaz", adding another one
- [
- [ 'FooBaz' => [ 'PriorCallback' ] ],
- [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
- [ 'FooBaz' => [ 'PriorCallback', 'FooBazCallback' ] ] + $merge,
- ],
- // No current hooks, adding one for "FooBaz" in verbose array format
- [
- [],
- [ 'Hooks' => [ 'FooBaz' => [ 'FooBazCallback' ] ] ] + self::$default,
- [ 'FooBaz' => [ 'FooBazCallback' ] ] + $merge,
- ],
- // Hook for "BarBaz", adding one for "FooBaz"
- [
- [ 'BarBaz' => [ 'BarBazCallback' ] ],
- [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
- [
- 'BarBaz' => [ 'BarBazCallback' ],
- 'FooBaz' => [ 'FooBazCallback' ],
- ] + $merge,
- ],
- // Callbacks for FooBaz wrapped in an array
- [
- [],
- [ 'Hooks' => [ 'FooBaz' => [ 'Callback1' ] ] ] + self::$default,
- [
- 'FooBaz' => [ 'Callback1' ],
- ] + $merge,
- ],
- // Multiple callbacks for FooBaz hook
- [
- [],
- [ 'Hooks' => [ 'FooBaz' => [ 'Callback1', 'Callback2' ] ] ] + self::$default,
- [
- 'FooBaz' => [ 'Callback1', 'Callback2' ],
- ] + $merge,
- ],
- ];
- }
-
- /**
- * @dataProvider provideRegisterHooks
- */
- public function testRegisterHooks( $pre, $info, $expected ) {
- $processor = new MockExtensionProcessor( [ 'wgHooks' => $pre ] );
- $processor->extractInfo( $this->dir, $info, 1 );
- $extracted = $processor->getExtractedInfo();
- $this->assertEquals( $expected, $extracted['globals']['wgHooks'] );
- }
-
- public function testExtractConfig1() {
- $processor = new ExtensionProcessor;
- $info = [
- 'config' => [
- 'Bar' => 'somevalue',
- 'Foo' => 10,
- '@IGNORED' => 'yes',
- ],
- ] + self::$default;
- $info2 = [
- 'config' => [
- '_prefix' => 'eg',
- 'Bar' => 'somevalue'
- ],
- 'name' => 'FooBar2',
- ];
- $processor->extractInfo( $this->dir, $info, 1 );
- $processor->extractInfo( $this->dir, $info2, 1 );
- $extracted = $processor->getExtractedInfo();
- $this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
- $this->assertEquals( 10, $extracted['globals']['wgFoo'] );
- $this->assertArrayNotHasKey( 'wg@IGNORED', $extracted['globals'] );
- // Custom prefix:
- $this->assertEquals( 'somevalue', $extracted['globals']['egBar'] );
- }
-
- public function testExtractConfig2() {
- $processor = new ExtensionProcessor;
- $info = [
- 'config' => [
- 'Bar' => [ 'value' => 'somevalue' ],
- 'Foo' => [ 'value' => 10 ],
- 'Path' => [ 'value' => 'foo.txt', 'path' => true ],
- 'Namespaces' => [
- 'value' => [
- '10' => true,
- '12' => false,
- ],
- 'merge_strategy' => 'array_plus',
- ],
- ],
- ] + self::$default;
- $info2 = [
- 'config' => [
- 'Bar' => [ 'value' => 'somevalue' ],
- ],
- 'config_prefix' => 'eg',
- 'name' => 'FooBar2',
- ];
- $processor->extractInfo( $this->dir, $info, 2 );
- $processor->extractInfo( $this->dir, $info2, 2 );
- $extracted = $processor->getExtractedInfo();
- $this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
- $this->assertEquals( 10, $extracted['globals']['wgFoo'] );
- $this->assertEquals( "{$this->dirname}/foo.txt", $extracted['globals']['wgPath'] );
- // Custom prefix:
- $this->assertEquals( 'somevalue', $extracted['globals']['egBar'] );
- $this->assertSame(
- [ 10 => true, 12 => false, ExtensionRegistry::MERGE_STRATEGY => 'array_plus' ],
- $extracted['globals']['wgNamespaces']
- );
- }
-
- /**
- * @expectedException RuntimeException
- */
- public function testDuplicateConfigKey1() {
- $processor = new ExtensionProcessor;
- $info = [
- 'config' => [
- 'Bar' => '',
- ]
- ] + self::$default;
- $info2 = [
- 'config' => [
- 'Bar' => 'g',
- ],
- 'name' => 'FooBar2',
- ];
- $processor->extractInfo( $this->dir, $info, 1 );
- $processor->extractInfo( $this->dir, $info2, 1 );
- }
-
- /**
- * @expectedException RuntimeException
- */
- public function testDuplicateConfigKey2() {
- $processor = new ExtensionProcessor;
- $info = [
- 'config' => [
- 'Bar' => [ 'value' => 'somevalue' ],
- ]
- ] + self::$default;
- $info2 = [
- 'config' => [
- 'Bar' => [ 'value' => 'somevalue' ],
- ],
- 'name' => 'FooBar2',
- ];
- $processor->extractInfo( $this->dir, $info, 2 );
- $processor->extractInfo( $this->dir, $info2, 2 );
- }
-
- public static function provideExtractExtensionMessagesFiles() {
- $dir = __DIR__ . '/FooBar/';
- return [
- [
- [ 'ExtensionMessagesFiles' => [ 'FooBarAlias' => 'FooBar.alias.php' ] ],
- [ 'wgExtensionMessagesFiles' => [ 'FooBarAlias' => $dir . 'FooBar.alias.php' ] ]
- ],
- [
- [
- 'ExtensionMessagesFiles' => [
- 'FooBarAlias' => 'FooBar.alias.php',
- 'FooBarMagic' => 'FooBar.magic.i18n.php',
- ],
- ],
- [
- 'wgExtensionMessagesFiles' => [
- 'FooBarAlias' => $dir . 'FooBar.alias.php',
- 'FooBarMagic' => $dir . 'FooBar.magic.i18n.php',
- ],
- ],
- ],
- ];
- }
-
- /**
- * @dataProvider provideExtractExtensionMessagesFiles
- */
- public function testExtractExtensionMessagesFiles( $input, $expected ) {
- $processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default, 1 );
- $out = $processor->getExtractedInfo();
- foreach ( $expected as $key => $value ) {
- $this->assertEquals( $value, $out['globals'][$key] );
- }
- }
-
- public static function provideExtractMessagesDirs() {
- $dir = __DIR__ . '/FooBar/';
- return [
- [
- [ 'MessagesDirs' => [ 'VisualEditor' => 'i18n' ] ],
- [ 'wgMessagesDirs' => [ 'VisualEditor' => [ $dir . 'i18n' ] ] ]
- ],
- [
- [ 'MessagesDirs' => [ 'VisualEditor' => [ 'i18n', 'foobar' ] ] ],
- [ 'wgMessagesDirs' => [ 'VisualEditor' => [ $dir . 'i18n', $dir . 'foobar' ] ] ]
- ],
- ];
- }
-
- /**
- * @dataProvider provideExtractMessagesDirs
- */
- public function testExtractMessagesDirs( $input, $expected ) {
- $processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default, 1 );
- $out = $processor->getExtractedInfo();
- foreach ( $expected as $key => $value ) {
- $this->assertEquals( $value, $out['globals'][$key] );
- }
- }
-
- public function testExtractCredits() {
- $processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, self::$default, 1 );
- $this->setExpectedException( Exception::class );
- $processor->extractInfo( $this->dir, self::$default, 1 );
- }
-
- /**
- * @dataProvider provideExtractResourceLoaderModules
- */
- public function testExtractResourceLoaderModules(
- $input,
- array $expectedGlobals,
- array $expectedAttribs = []
- ) {
- $processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default, 1 );
- $out = $processor->getExtractedInfo();
- foreach ( $expectedGlobals as $key => $value ) {
- $this->assertEquals( $value, $out['globals'][$key] );
- }
- foreach ( $expectedAttribs as $key => $value ) {
- $this->assertEquals( $value, $out['attributes'][$key] );
- }
- }
-
- public static function provideExtractResourceLoaderModules() {
- $dir = __DIR__ . '/FooBar';
- return [
- // Generic module with localBasePath/remoteExtPath specified
- [
- // Input
- [
- 'ResourceModules' => [
- 'test.foo' => [
- 'styles' => 'foobar.js',
- 'localBasePath' => '',
- 'remoteExtPath' => 'FooBar',
- ],
- ],
- ],
- // Expected
- [
- 'wgResourceModules' => [
- 'test.foo' => [
- 'styles' => 'foobar.js',
- 'localBasePath' => $dir,
- 'remoteExtPath' => 'FooBar',
- ],
- ],
- ],
- ],
- // ResourceFileModulePaths specified:
- [
- // Input
- [
- 'ResourceFileModulePaths' => [
- 'localBasePath' => 'modules',
- 'remoteExtPath' => 'FooBar/modules',
- ],
- 'ResourceModules' => [
- // No paths
- 'test.foo' => [
- 'styles' => 'foo.js',
- ],
- // Different paths set
- 'test.bar' => [
- 'styles' => 'bar.js',
- 'localBasePath' => 'subdir',
- 'remoteExtPath' => 'FooBar/subdir',
- ],
- // Custom class with no paths set
- 'test.class' => [
- 'class' => 'FooBarModule',
- 'extra' => 'argument',
- ],
- // Custom class with a localBasePath
- 'test.class.with.path' => [
- 'class' => 'FooBarPathModule',
- 'extra' => 'argument',
- 'localBasePath' => '',
- ]
- ],
- ],
- // Expected
- [
- 'wgResourceModules' => [
- 'test.foo' => [
- 'styles' => 'foo.js',
- 'localBasePath' => "$dir/modules",
- 'remoteExtPath' => 'FooBar/modules',
- ],
- 'test.bar' => [
- 'styles' => 'bar.js',
- 'localBasePath' => "$dir/subdir",
- 'remoteExtPath' => 'FooBar/subdir',
- ],
- 'test.class' => [
- 'class' => 'FooBarModule',
- 'extra' => 'argument',
- 'localBasePath' => "$dir/modules",
- 'remoteExtPath' => 'FooBar/modules',
- ],
- 'test.class.with.path' => [
- 'class' => 'FooBarPathModule',
- 'extra' => 'argument',
- 'localBasePath' => $dir,
- 'remoteExtPath' => 'FooBar/modules',
- ]
- ],
- ],
- ],
- // ResourceModuleSkinStyles with file module paths
- [
- // Input
- [
- 'ResourceFileModulePaths' => [
- 'localBasePath' => '',
- 'remoteSkinPath' => 'FooBar',
- ],
- 'ResourceModuleSkinStyles' => [
- 'foobar' => [
- 'test.foo' => 'foo.css',
- ]
- ],
- ],
- // Expected
- [
- 'wgResourceModuleSkinStyles' => [
- 'foobar' => [
- 'test.foo' => 'foo.css',
- 'localBasePath' => $dir,
- 'remoteSkinPath' => 'FooBar',
- ],
- ],
- ],
- ],
- // ResourceModuleSkinStyles with file module paths and an override
- [
- // Input
- [
- 'ResourceFileModulePaths' => [
- 'localBasePath' => '',
- 'remoteSkinPath' => 'FooBar',
- ],
- 'ResourceModuleSkinStyles' => [
- 'foobar' => [
- 'test.foo' => 'foo.css',
- 'remoteSkinPath' => 'BarFoo'
- ],
- ],
- ],
- // Expected
- [
- 'wgResourceModuleSkinStyles' => [
- 'foobar' => [
- 'test.foo' => 'foo.css',
- 'localBasePath' => $dir,
- 'remoteSkinPath' => 'BarFoo',
- ],
- ],
- ],
- ],
- 'QUnit test module' => [
- // Input
- [
- 'QUnitTestModule' => [
- 'localBasePath' => '',
- 'remoteExtPath' => 'Foo',
- 'scripts' => 'bar.js',
- ],
- ],
- // Expected
- [],
- [
- 'QUnitTestModules' => [
- 'test.FooBar' => [
- 'localBasePath' => $dir,
- 'remoteExtPath' => 'Foo',
- 'scripts' => 'bar.js',
- ],
- ],
- ],
- ],
- ];
- }
-
- public static function provideSetToGlobal() {
- return [
- [
- [ 'wgAPIModules', 'wgAvailableRights' ],
- [],
- [
- 'APIModules' => [ 'foobar' => 'ApiFooBar' ],
- 'AvailableRights' => [ 'foobar', 'unfoobar' ],
- ],
- [
- 'wgAPIModules' => [ 'foobar' => 'ApiFooBar' ],
- 'wgAvailableRights' => [ 'foobar', 'unfoobar' ],
- ],
- ],
- [
- [ 'wgAPIModules', 'wgAvailableRights' ],
- [
- 'wgAPIModules' => [ 'barbaz' => 'ApiBarBaz' ],
- 'wgAvailableRights' => [ 'barbaz' ]
- ],
- [
- 'APIModules' => [ 'foobar' => 'ApiFooBar' ],
- 'AvailableRights' => [ 'foobar', 'unfoobar' ],
- ],
- [
- 'wgAPIModules' => [ 'barbaz' => 'ApiBarBaz', 'foobar' => 'ApiFooBar' ],
- 'wgAvailableRights' => [ 'barbaz', 'foobar', 'unfoobar' ],
- ],
- ],
- [
- [ 'wgGroupPermissions' ],
- [
- 'wgGroupPermissions' => [
- 'sysop' => [ 'delete' ]
- ],
- ],
- [
- 'GroupPermissions' => [
- 'sysop' => [ 'undelete' ],
- 'user' => [ 'edit' ]
- ],
- ],
- [
- 'wgGroupPermissions' => [
- 'sysop' => [ 'delete', 'undelete' ],
- 'user' => [ 'edit' ]
- ],
- ]
- ]
- ];
- }
-
- /**
- * Attributes under manifest_version 2
- */
- public function testExtractAttributes() {
- $processor = new ExtensionProcessor();
- // Load FooBar extension
- $processor->extractInfo( $this->dir, [ 'name' => 'FooBar' ], 2 );
- $processor->extractInfo(
- $this->dir,
- [
- 'name' => 'Baz',
- 'attributes' => [
- // Loaded
- 'FooBar' => [
- 'Plugins' => [
- 'ext.baz.foobar',
- ],
- ],
- // Not loaded
- 'FizzBuzz' => [
- 'MorePlugins' => [
- 'ext.baz.fizzbuzz',
- ],
- ],
- ],
- ],
- 2
- );
-
- $info = $processor->getExtractedInfo();
- $this->assertArrayHasKey( 'FooBarPlugins', $info['attributes'] );
- $this->assertSame( [ 'ext.baz.foobar' ], $info['attributes']['FooBarPlugins'] );
- $this->assertArrayNotHasKey( 'FizzBuzzMorePlugins', $info['attributes'] );
- }
-
- /**
- * Attributes under manifest_version 1
- */
- public function testAttributes1() {
- $processor = new ExtensionProcessor();
- $processor->extractInfo(
- $this->dir,
- [
- 'name' => 'FooBar',
- 'FooBarPlugins' => [
- 'ext.baz.foobar',
- ],
- 'FizzBuzzMorePlugins' => [
- 'ext.baz.fizzbuzz',
- ],
- ],
- 1
- );
- $processor->extractInfo(
- $this->dir,
- [
- 'name' => 'FooBar2',
- 'FizzBuzzMorePlugins' => [
- 'ext.bar.fizzbuzz',
- ]
- ],
- 1
- );
-
- $info = $processor->getExtractedInfo();
- $this->assertArrayHasKey( 'FooBarPlugins', $info['attributes'] );
- $this->assertSame( [ 'ext.baz.foobar' ], $info['attributes']['FooBarPlugins'] );
- $this->assertArrayHasKey( 'FizzBuzzMorePlugins', $info['attributes'] );
- $this->assertSame(
- [ 'ext.baz.fizzbuzz', 'ext.bar.fizzbuzz' ],
- $info['attributes']['FizzBuzzMorePlugins']
- );
- }
-
- public function testAttributes1_notarray() {
- $processor = new ExtensionProcessor();
- $this->setExpectedException(
- InvalidArgumentException::class,
- "The value for 'FooBarPlugins' should be an array (from {$this->dir})"
- );
- $processor->extractInfo(
- $this->dir,
- [
- 'FooBarPlugins' => 'ext.baz.foobar',
- ] + self::$default,
- 1
- );
- }
-
- public function testExtractPathBasedGlobal() {
- $processor = new ExtensionProcessor();
- $processor->extractInfo(
- $this->dir,
- [
- 'ParserTestFiles' => [
- 'tests/parserTests.txt',
- 'tests/extraParserTests.txt',
- ],
- 'ServiceWiringFiles' => [
- 'includes/ServiceWiring.php'
- ],
- ] + self::$default,
- 1
- );
- $globals = $processor->getExtractedInfo()['globals'];
- $this->assertArrayHasKey( 'wgParserTestFiles', $globals );
- $this->assertSame( [
- "{$this->dirname}/tests/parserTests.txt",
- "{$this->dirname}/tests/extraParserTests.txt"
- ], $globals['wgParserTestFiles'] );
- $this->assertArrayHasKey( 'wgServiceWiringFiles', $globals );
- $this->assertSame( [
- "{$this->dirname}/includes/ServiceWiring.php"
- ], $globals['wgServiceWiringFiles'] );
- }
-
- public function testGetRequirements() {
- $info = self::$default + [
- 'requires' => [
- 'MediaWiki' => '>= 1.25.0',
- 'platform' => [
- 'php' => '>= 5.5.9'
- ],
- 'extensions' => [
- 'Bar' => '*'
- ]
- ]
- ];
- $processor = new ExtensionProcessor();
- $this->assertSame(
- $info['requires'],
- $processor->getRequirements( $info, false )
- );
- $this->assertSame(
- [],
- $processor->getRequirements( [], false )
- );
- }
-
- public function testGetDevRequirements() {
- $info = self::$default + [
- 'dev-requires' => [
- 'MediaWiki' => '>= 1.31.0',
- 'platform' => [
- 'ext-foo' => '*',
- ],
- 'skins' => [
- 'Baz' => '*',
- ],
- 'extensions' => [
- 'Biz' => '*',
- ],
- ],
- ];
- $processor = new ExtensionProcessor();
- $this->assertSame(
- $info['dev-requires'],
- $processor->getRequirements( $info, true )
- );
- // Set some standard requirements, so we can test merging
- $info['requires'] = [
- 'MediaWiki' => '>= 1.25.0',
- 'platform' => [
- 'php' => '>= 5.5.9'
- ],
- 'extensions' => [
- 'Bar' => '*'
- ]
- ];
- $this->assertSame(
- [
- 'MediaWiki' => '>= 1.25.0 >= 1.31.0',
- 'platform' => [
- 'php' => '>= 5.5.9',
- 'ext-foo' => '*',
- ],
- 'extensions' => [
- 'Bar' => '*',
- 'Biz' => '*',
- ],
- 'skins' => [
- 'Baz' => '*',
- ],
- ],
- $processor->getRequirements( $info, true )
- );
-
- // If there's no dev-requires, it just returns requires
- unset( $info['dev-requires'] );
- $this->assertSame(
- $info['requires'],
- $processor->getRequirements( $info, true )
- );
- }
-
- public function testGetExtraAutoloaderPaths() {
- $processor = new ExtensionProcessor();
- $this->assertSame(
- [ "{$this->dirname}/vendor/autoload.php" ],
- $processor->getExtraAutoloaderPaths( $this->dirname, [
- 'load_composer_autoloader' => true,
- ] )
- );
- }
-
- /**
- * Verify that extension.schema.json is in sync with ExtensionProcessor
- *
- * @coversNothing
- */
- public function testGlobalSettingsDocumentedInSchema() {
- global $IP;
- $globalSettings = TestingAccessWrapper::newFromClass(
- ExtensionProcessor::class )->globalSettings;
-
- $version = ExtensionRegistry::MANIFEST_VERSION;
- $schema = FormatJson::decode(
- file_get_contents( "$IP/docs/extension.schema.v$version.json" ),
- true
- );
- $missing = [];
- foreach ( $globalSettings as $global ) {
- if ( !isset( $schema['properties'][$global] ) ) {
- $missing[] = $global;
- }
- }
-
- $this->assertEquals( [], $missing,
- "The following global settings are not documented in docs/extension.schema.json" );
- }
-}
-
-/**
- * Allow overriding the default value of $this->globals
- * so we can test merging
- */
-class MockExtensionProcessor extends ExtensionProcessor {
- public function __construct( $globals = [] ) {
- $this->globals = $globals + $this->globals;
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @group Search
- * @covers SearchIndexFieldDefinition
- */
-class SearchIndexFieldTest extends MediaWikiTestCase {
-
- public function getMergeCases() {
- return [
- [ 0, 'test', 0, 'test', true ],
- [ SearchIndexField::INDEX_TYPE_NESTED, 'test',
- SearchIndexField::INDEX_TYPE_NESTED, 'test', false ],
- [ 0, 'test', 0, 'test2', true ],
- [ 0, 'test', 1, 'test', false ],
- ];
- }
-
- /**
- * @dataProvider getMergeCases
- * @param int $t1
- * @param string $n1
- * @param int $t2
- * @param string $n2
- * @param bool $result
- */
- public function testMerge( $t1, $n1, $t2, $n2, $result ) {
- $field1 =
- $this->getMockBuilder( SearchIndexFieldDefinition::class )
- ->setMethods( [ 'getMapping' ] )
- ->setConstructorArgs( [ $n1, $t1 ] )
- ->getMock();
- $field2 =
- $this->getMockBuilder( SearchIndexFieldDefinition::class )
- ->setMethods( [ 'getMapping' ] )
- ->setConstructorArgs( [ $n2, $t2 ] )
- ->getMock();
-
- if ( $result ) {
- $this->assertNotFalse( $field1->merge( $field2 ) );
- } else {
- $this->assertFalse( $field1->merge( $field2 ) );
- }
-
- $field1->setFlag( 0xFF );
- $this->assertFalse( $field1->merge( $field2 ) );
-
- $field1->setMergeCallback(
- function ( $a, $b ) {
- return "test";
- }
- );
- $this->assertEquals( "test", $field1->merge( $field2 ) );
- }
-
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Session;
-
-use MediaWikiTestCase;
-
-/**
- * @group Session
- * @covers MediaWiki\Session\MetadataMergeException
- */
-class MetadataMergeExceptionTest extends MediaWikiTestCase {
-
- public function testBasics() {
- $data = [ 'foo' => 'bar' ];
-
- $ex = new MetadataMergeException();
- $this->assertInstanceOf( \UnexpectedValueException::class, $ex );
- $this->assertSame( [], $ex->getContext() );
-
- $ex2 = new MetadataMergeException( 'Message', 42, $ex, $data );
- $this->assertSame( 'Message', $ex2->getMessage() );
- $this->assertSame( 42, $ex2->getCode() );
- $this->assertSame( $ex, $ex2->getPrevious() );
- $this->assertSame( $data, $ex2->getContext() );
-
- $ex->setContext( $data );
- $this->assertSame( $data, $ex->getContext() );
- }
-
-}
+++ /dev/null
-<?php
-
-namespace MediaWiki\Session;
-
-use MediaWikiTestCase;
-
-/**
- * @group Session
- * @covers MediaWiki\Session\SessionId
- */
-class SessionIdTest extends MediaWikiTestCase {
-
- public function testEverything() {
- $id = new SessionId( 'foo' );
- $this->assertSame( 'foo', $id->getId() );
- $this->assertSame( 'foo', (string)$id );
- $id->setId( 'bar' );
- $this->assertSame( 'bar', $id->getId() );
- $this->assertSame( 'bar', (string)$id );
- }
-
-}
+++ /dev/null
-<?php
-
-class SkinFactoryTest extends MediaWikiTestCase {
-
- /**
- * @covers SkinFactory::register
- */
- public function testRegister() {
- $factory = new SkinFactory();
- $factory->register( 'fallback', 'Fallback', function () {
- return new SkinFallback();
- } );
- $this->assertTrue( true ); // No exception thrown
- $this->setExpectedException( InvalidArgumentException::class );
- $factory->register( 'invalid', 'Invalid', 'Invalid callback' );
- }
-
- /**
- * @covers SkinFactory::makeSkin
- */
- public function testMakeSkinWithNoBuilders() {
- $factory = new SkinFactory();
- $this->setExpectedException( SkinException::class );
- $factory->makeSkin( 'nobuilderregistered' );
- }
-
- /**
- * @covers SkinFactory::makeSkin
- */
- public function testMakeSkinWithInvalidCallback() {
- $factory = new SkinFactory();
- $factory->register( 'unittest', 'Unittest', function () {
- return true; // Not a Skin object
- } );
- $this->setExpectedException( UnexpectedValueException::class );
- $factory->makeSkin( 'unittest' );
- }
-
- /**
- * @covers SkinFactory::makeSkin
- */
- public function testMakeSkinWithValidCallback() {
- $factory = new SkinFactory();
- $factory->register( 'testfallback', 'TestFallback', function () {
- return new SkinFallback();
- } );
-
- $skin = $factory->makeSkin( 'testfallback' );
- $this->assertInstanceOf( Skin::class, $skin );
- $this->assertInstanceOf( SkinFallback::class, $skin );
- $this->assertEquals( 'fallback', $skin->getSkinName() );
- }
-
- /**
- * @covers Skin::__construct
- * @covers Skin::getSkinName
- */
- public function testGetSkinName() {
- $skin = new SkinFallback();
- $this->assertEquals( 'fallback', $skin->getSkinName(), 'Default' );
- $skin = new SkinFallback( 'testname' );
- $this->assertEquals( 'testname', $skin->getSkinName(), 'Constructor argument' );
- }
-
- /**
- * @covers SkinFactory::getSkinNames
- */
- public function testGetSkinNames() {
- $factory = new SkinFactory();
- // A fake callback we can use that will never be called
- $callback = function () {
- // NOP
- };
- $factory->register( 'skin1', 'Skin1', $callback );
- $factory->register( 'skin2', 'Skin2', $callback );
- $names = $factory->getSkinNames();
- $this->assertArrayHasKey( 'skin1', $names );
- $this->assertArrayHasKey( 'skin2', $names );
- $this->assertEquals( 'Skin1', $names['skin1'] );
- $this->assertEquals( 'Skin2', $names['skin2'] );
- }
-}
+++ /dev/null
-<?php
-/**
- * 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
- * @author This, that and the other
- */
-
-/**
- * @covers ForeignTitle
- *
- * @group Title
- */
-class ForeignTitleTest extends MediaWikiTestCase {
-
- public function basicProvider() {
- return [
- [
- new ForeignTitle( 20, 'Contributor', 'JohnDoe' ),
- 20, 'Contributor', 'JohnDoe'
- ],
- [
- new ForeignTitle( '1', 'Discussion', 'Capital' ),
- 1, 'Discussion', 'Capital'
- ],
- [
- new ForeignTitle( 0, '', 'MainNamespace' ),
- 0, '', 'MainNamespace'
- ],
- [
- new ForeignTitle( 4, 'Some ns', 'Article title with spaces' ),
- 4, 'Some_ns', 'Article_title_with_spaces'
- ],
- ];
- }
-
- /**
- * @dataProvider basicProvider
- */
- public function testBasic( ForeignTitle $title, $expectedId, $expectedName,
- $expectedText
- ) {
- $this->assertEquals( true, $title->isNamespaceIdKnown() );
- $this->assertEquals( $expectedId, $title->getNamespaceId() );
- $this->assertEquals( $expectedName, $title->getNamespaceName() );
- $this->assertEquals( $expectedText, $title->getText() );
- }
-
- public function testUnknownNamespaceCheck() {
- $title = new ForeignTitle( null, 'this', 'that' );
-
- $this->assertEquals( false, $title->isNamespaceIdKnown() );
- $this->assertEquals( 'this', $title->getNamespaceName() );
- $this->assertEquals( 'that', $title->getText() );
- }
-
- public function testUnknownNamespaceError() {
- $this->setExpectedException( MWException::class );
- $title = new ForeignTitle( null, 'this', 'that' );
- $title->getNamespaceId();
- }
-
- public function fullTextProvider() {
- return [
- [
- new ForeignTitle( 20, 'Contributor', 'JohnDoe' ),
- 'Contributor:JohnDoe'
- ],
- [
- new ForeignTitle( '1', 'Discussion', 'Capital' ),
- 'Discussion:Capital'
- ],
- [
- new ForeignTitle( 0, '', 'MainNamespace' ),
- 'MainNamespace'
- ],
- [
- new ForeignTitle( 4, 'Some ns', 'Article title with spaces' ),
- 'Some_ns:Article_title_with_spaces'
- ],
- ];
- }
-
- /**
- * @dataProvider fullTextProvider
- */
- public function testFullText( ForeignTitle $title, $fullText ) {
- $this->assertEquals( $fullText, $title->getFullText() );
- }
-}
+++ /dev/null
-<?php
-/**
- * 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
- * @author This, that and the other
- */
-
-/**
- * @covers NamespaceAwareForeignTitleFactory
- *
- * @group Title
- */
-class NamespaceAwareForeignTitleFactoryTest extends MediaWikiTestCase {
-
- public function basicProvider() {
- return [
- [
- 'MainNamespaceArticle', 0,
- new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
- ],
- [
- 'MainNamespaceArticle', null,
- new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
- ],
- [
- 'Magic:_The_Gathering', 0,
- new ForeignTitle( 0, '', 'Magic:_The_Gathering' ),
- ],
- [
- 'Talk:Nice_talk', 1,
- new ForeignTitle( 1, 'Talk', 'Nice_talk' ),
- ],
- [
- 'Talk:Magic:_The_Gathering', 1,
- new ForeignTitle( 1, 'Talk', 'Magic:_The_Gathering' ),
- ],
- [
- 'Bogus:Nice_talk', 0,
- new ForeignTitle( 0, '', 'Bogus:Nice_talk' ),
- ],
- [
- 'Bogus:Nice_talk', null,
- new ForeignTitle( 9000, 'Bogus', 'Nice_talk' ),
- ],
- [
- 'Bogus:Nice_talk', 4,
- new ForeignTitle( 4, 'Bogus', 'Nice_talk' ),
- ],
- [
- 'Bogus:Nice_talk', 1,
- new ForeignTitle( 1, 'Talk', 'Nice_talk' ),
- ],
- // Misconfigured wiki with unregistered namespace (T114115)
- [
- 'Nice_talk', 1234,
- new ForeignTitle( 1234, 'Ns1234', 'Nice_talk' ),
- ],
- ];
- }
-
- /**
- * @dataProvider basicProvider
- */
- public function testBasic( $title, $ns, ForeignTitle $foreignTitle ) {
- $foreignNamespaces = [
- 0 => '', 1 => 'Talk', 100 => 'Portal', 9000 => 'Bogus'
- ];
-
- $factory = new NamespaceAwareForeignTitleFactory( $foreignNamespaces );
- $testTitle = $factory->createForeignTitle( $title, $ns );
-
- $this->assertEquals( $testTitle->isNamespaceIdKnown(),
- $foreignTitle->isNamespaceIdKnown() );
-
- if (
- $testTitle->isNamespaceIdKnown() &&
- $foreignTitle->isNamespaceIdKnown()
- ) {
- $this->assertEquals( $testTitle->getNamespaceId(),
- $foreignTitle->getNamespaceId() );
- }
-
- $this->assertEquals( $testTitle->getNamespaceName(),
- $foreignTitle->getNamespaceName() );
- $this->assertEquals( $testTitle->getText(), $foreignTitle->getText() );
- }
-}
+++ /dev/null
-<?php
-/**
- * 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
- * @author Daniel Kinzler
- */
-
-/**
- * @covers TitleValue
- *
- * @group Title
- */
-class TitleValueTest extends MediaWikiTestCase {
-
- public function goodConstructorProvider() {
- return [
- [ NS_MAIN, '', 'fragment', '', true, false ],
- [ NS_USER, 'TestThis', 'stuff', '', true, false ],
- [ NS_USER, 'TestThis', '', 'baz', false, true ],
- ];
- }
-
- /**
- * @dataProvider goodConstructorProvider
- */
- public function testConstruction( $ns, $text, $fragment, $interwiki, $hasFragment,
- $hasInterwiki
- ) {
- $title = new TitleValue( $ns, $text, $fragment, $interwiki );
-
- $this->assertEquals( $ns, $title->getNamespace() );
- $this->assertTrue( $title->inNamespace( $ns ) );
- $this->assertEquals( $text, $title->getText() );
- $this->assertEquals( $fragment, $title->getFragment() );
- $this->assertEquals( $hasFragment, $title->hasFragment() );
- $this->assertEquals( $interwiki, $title->getInterwiki() );
- $this->assertEquals( $hasInterwiki, $title->isExternal() );
- }
-
- public function badConstructorProvider() {
- return [
- [ 'foo', 'title', 'fragment', '' ],
- [ null, 'title', 'fragment', '' ],
- [ 2.3, 'title', 'fragment', '' ],
-
- [ NS_MAIN, 5, 'fragment', '' ],
- [ NS_MAIN, null, 'fragment', '' ],
- [ NS_USER, '', 'fragment', '' ],
- [ NS_MAIN, 'foo bar', '', '' ],
- [ NS_MAIN, 'bar_', '', '' ],
- [ NS_MAIN, '_foo', '', '' ],
- [ NS_MAIN, ' eek ', '', '' ],
-
- [ NS_MAIN, 'title', 5, '' ],
- [ NS_MAIN, 'title', null, '' ],
- [ NS_MAIN, 'title', [], '' ],
-
- [ NS_MAIN, 'title', '', 5 ],
- [ NS_MAIN, 'title', null, 5 ],
- [ NS_MAIN, 'title', [], 5 ],
- ];
- }
-
- /**
- * @dataProvider badConstructorProvider
- */
- public function testConstructionErrors( $ns, $text, $fragment, $interwiki ) {
- $this->setExpectedException( InvalidArgumentException::class );
- new TitleValue( $ns, $text, $fragment, $interwiki );
- }
-
- public function fragmentTitleProvider() {
- return [
- [ new TitleValue( NS_MAIN, 'Test' ), 'foo' ],
- [ new TitleValue( NS_TALK, 'Test', 'foo' ), '' ],
- [ new TitleValue( NS_CATEGORY, 'Test', 'foo' ), 'bar' ],
- ];
- }
-
- /**
- * @dataProvider fragmentTitleProvider
- */
- public function testCreateFragmentTitle( TitleValue $title, $fragment ) {
- $fragmentTitle = $title->createFragmentTarget( $fragment );
-
- $this->assertEquals( $title->getNamespace(), $fragmentTitle->getNamespace() );
- $this->assertEquals( $title->getText(), $fragmentTitle->getText() );
- $this->assertEquals( $fragment, $fragmentTitle->getFragment() );
- }
-
- public function getTextProvider() {
- return [
- [ 'Foo', 'Foo' ],
- [ 'Foo_Bar', 'Foo Bar' ],
- ];
- }
-
- /**
- * @dataProvider getTextProvider
- */
- public function testGetText( $dbkey, $text ) {
- $title = new TitleValue( NS_MAIN, $dbkey );
-
- $this->assertEquals( $text, $title->getText() );
- }
-
- public function provideTestToString() {
- yield [
- new TitleValue( 0, 'Foo' ),
- '0:Foo'
- ];
- yield [
- new TitleValue( 1, 'Bar_Baz' ),
- '1:Bar_Baz'
- ];
- yield [
- new TitleValue( 9, 'JoJo', 'Frag' ),
- '9:JoJo#Frag'
- ];
- yield [
- new TitleValue( 200, 'tea', 'Fragment', 'wikicode' ),
- 'wikicode:200:tea#Fragment'
- ];
- }
-
- /**
- * @dataProvider provideTestToString
- */
- public function testToString( TitleValue $value, $expected ) {
- $this->assertSame(
- $expected,
- $value->__toString()
- );
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @author Addshore
- * @covers UserArrayFromResult
- */
-class UserArrayFromResultTest extends MediaWikiTestCase {
-
- private function getMockResultWrapper( $row = null, $numRows = 1 ) {
- $resultWrapper = $this->getMockBuilder( Wikimedia\Rdbms\ResultWrapper::class )
- ->disableOriginalConstructor();
-
- $resultWrapper = $resultWrapper->getMock();
- $resultWrapper->expects( $this->atLeastOnce() )
- ->method( 'current' )
- ->will( $this->returnValue( $row ) );
- $resultWrapper->expects( $this->any() )
- ->method( 'numRows' )
- ->will( $this->returnValue( $numRows ) );
-
- return $resultWrapper;
- }
-
- private function getRowWithUsername( $username = 'fooUser' ) {
- $row = new stdClass();
- $row->user_name = $username;
- return $row;
- }
-
- /**
- * @covers UserArrayFromResult::__construct
- */
- public function testConstructionWithFalseRow() {
- $row = false;
- $resultWrapper = $this->getMockResultWrapper( $row );
-
- $object = new UserArrayFromResult( $resultWrapper );
-
- $this->assertEquals( $resultWrapper, $object->res );
- $this->assertSame( 0, $object->key );
- $this->assertEquals( $row, $object->current );
- }
-
- /**
- * @covers UserArrayFromResult::__construct
- */
- public function testConstructionWithRow() {
- $username = 'addshore';
- $row = $this->getRowWithUsername( $username );
- $resultWrapper = $this->getMockResultWrapper( $row );
-
- $object = new UserArrayFromResult( $resultWrapper );
-
- $this->assertEquals( $resultWrapper, $object->res );
- $this->assertSame( 0, $object->key );
- $this->assertInstanceOf( User::class, $object->current );
- $this->assertEquals( $username, $object->current->mName );
- }
-
- public static function provideNumberOfRows() {
- return [
- [ 0 ],
- [ 1 ],
- [ 122 ],
- ];
- }
-
- /**
- * @dataProvider provideNumberOfRows
- * @covers UserArrayFromResult::count
- */
- public function testCountWithVaryingValues( $numRows ) {
- $object = new UserArrayFromResult( $this->getMockResultWrapper(
- $this->getRowWithUsername(),
- $numRows
- ) );
- $this->assertEquals( $numRows, $object->count() );
- }
-
- /**
- * @covers UserArrayFromResult::current
- */
- public function testCurrentAfterConstruction() {
- $username = 'addshore';
- $userRow = $this->getRowWithUsername( $username );
- $object = new UserArrayFromResult( $this->getMockResultWrapper( $userRow ) );
- $this->assertInstanceOf( User::class, $object->current() );
- $this->assertEquals( $username, $object->current()->mName );
- }
-
- public function provideTestValid() {
- return [
- [ $this->getRowWithUsername(), true ],
- [ false, false ],
- ];
- }
-
- /**
- * @dataProvider provideTestValid
- * @covers UserArrayFromResult::valid
- */
- public function testValid( $input, $expected ) {
- $object = new UserArrayFromResult( $this->getMockResultWrapper( $input ) );
- $this->assertEquals( $expected, $object->valid() );
- }
-
- // @todo unit test for key()
- // @todo unit test for next()
- // @todo unit test for rewind()
-}
+++ /dev/null
-<?php
-
-use MediaWiki\User\UserIdentityValue;
-
-/**
- * @author Addshore
- *
- * @covers NoWriteWatchedItemStore
- */
-class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
-
- public function testAddWatch() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->never() )->method( 'addWatch' );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $this->setExpectedException( DBReadOnlyError::class );
- $noWriteService->addWatch(
- new UserIdentityValue( 1, 'MockUser', 0 ), new TitleValue( 0, 'Foo' ) );
- }
-
- public function testAddWatchBatchForUser() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->never() )->method( 'addWatchBatchForUser' );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $this->setExpectedException( DBReadOnlyError::class );
- $noWriteService->addWatchBatchForUser( new UserIdentityValue( 1, 'MockUser', 0 ), [] );
- }
-
- public function testRemoveWatch() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->never() )->method( 'removeWatch' );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $this->setExpectedException( DBReadOnlyError::class );
- $noWriteService->removeWatch(
- new UserIdentityValue( 1, 'MockUser', 0 ), new TitleValue( 0, 'Foo' ) );
- }
-
- public function testSetNotificationTimestampsForUser() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->never() )->method( 'setNotificationTimestampsForUser' );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $this->setExpectedException( DBReadOnlyError::class );
- $noWriteService->setNotificationTimestampsForUser(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- 'timestamp',
- []
- );
- }
-
- public function testUpdateNotificationTimestamp() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->never() )->method( 'updateNotificationTimestamp' );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $this->setExpectedException( DBReadOnlyError::class );
- $noWriteService->updateNotificationTimestamp(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- new TitleValue( 0, 'Foo' ),
- 'timestamp'
- );
- }
-
- public function testResetNotificationTimestamp() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->never() )->method( 'resetNotificationTimestamp' );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $this->setExpectedException( DBReadOnlyError::class );
- $noWriteService->resetNotificationTimestamp(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- new TitleValue( 0, 'Foo' )
- );
- }
-
- public function testCountWatchedItems() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )->method( 'countWatchedItems' )->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->countWatchedItems(
- new UserIdentityValue( 1, 'MockUser', 0 )
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testCountWatchers() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )->method( 'countWatchers' )->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->countWatchers(
- new TitleValue( 0, 'Foo' )
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testCountVisitingWatchers() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )
- ->method( 'countVisitingWatchers' )
- ->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->countVisitingWatchers(
- new TitleValue( 0, 'Foo' ),
- 9
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testCountWatchersMultiple() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )
- ->method( 'countVisitingWatchersMultiple' )
- ->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->countWatchersMultiple(
- [ new TitleValue( 0, 'Foo' ) ],
- []
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testCountVisitingWatchersMultiple() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )
- ->method( 'countVisitingWatchersMultiple' )
- ->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->countVisitingWatchersMultiple(
- [ [ new TitleValue( 0, 'Foo' ), 99 ] ],
- 11
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testGetWatchedItem() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )->method( 'getWatchedItem' )->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->getWatchedItem(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- new TitleValue( 0, 'Foo' )
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testLoadWatchedItem() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )->method( 'loadWatchedItem' )->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->loadWatchedItem(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- new TitleValue( 0, 'Foo' )
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testGetWatchedItemsForUser() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )
- ->method( 'getWatchedItemsForUser' )
- ->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->getWatchedItemsForUser(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- []
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testIsWatched() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )->method( 'isWatched' )->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->isWatched(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- new TitleValue( 0, 'Foo' )
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testGetNotificationTimestampsBatch() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )
- ->method( 'getNotificationTimestampsBatch' )
- ->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->getNotificationTimestampsBatch(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- [ new TitleValue( 0, 'Foo' ) ]
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testCountUnreadNotifications() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $innerService->expects( $this->once() )
- ->method( 'countUnreadNotifications' )
- ->willReturn( __METHOD__ );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $return = $noWriteService->countUnreadNotifications(
- new UserIdentityValue( 1, 'MockUser', 0 ),
- 88
- );
- $this->assertEquals( __METHOD__, $return );
- }
-
- public function testDuplicateAllAssociatedEntries() {
- /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
- $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
- $noWriteService = new NoWriteWatchedItemStore( $innerService );
-
- $this->setExpectedException( DBReadOnlyError::class );
- $noWriteService->duplicateAllAssociatedEntries(
- new TitleValue( 0, 'Foo' ),
- new TitleValue( 0, 'Bar' )
- );
- }
-
-}
*
* @author Katie Filbert < aude.wiki@gmail.com >
*/
-class SpecialPageAliasTest extends MediaWikiTestCase {
+class SpecialPageAliasTest extends \MediaWikiUnitTestCase {
/**
* @coversNothing
--- /dev/null
+<?php
+/**
+ * Copyright @ 2011 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
+ */
+
+class FauxResponseTest extends \MediaWikiUnitTestCase {
+ /** @var FauxResponse */
+ protected $response;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->response = new FauxResponse;
+ }
+
+ /**
+ * @covers FauxResponse::setCookie
+ * @covers FauxResponse::getCookie
+ * @covers FauxResponse::getCookieData
+ * @covers FauxResponse::getCookies
+ */
+ public function testCookie() {
+ $expire = time() + 100;
+ $cookie = [
+ 'value' => 'val',
+ 'path' => '/path',
+ 'domain' => 'domain',
+ 'secure' => true,
+ 'httpOnly' => false,
+ 'raw' => false,
+ 'expire' => $expire,
+ ];
+
+ $this->assertEquals( null, $this->response->getCookie( 'xkey' ), 'Non-existing cookie' );
+ $this->response->setCookie( 'key', 'val', $expire, [
+ 'prefix' => 'x',
+ 'path' => '/path',
+ 'domain' => 'domain',
+ 'secure' => 1,
+ 'httpOnly' => 0,
+ ] );
+ $this->assertEquals( 'val', $this->response->getCookie( 'xkey' ), 'Existing cookie' );
+ $this->assertEquals( $cookie, $this->response->getCookieData( 'xkey' ),
+ 'Existing cookie (data)' );
+ $this->assertEquals( [ 'xkey' => $cookie ], $this->response->getCookies(),
+ 'Existing cookies' );
+ }
+
+ /**
+ * @covers FauxResponse::getheader
+ * @covers FauxResponse::header
+ */
+ public function testHeader() {
+ $this->assertEquals( null, $this->response->getHeader( 'Location' ), 'Non-existing header' );
+
+ $this->response->header( 'Location: http://localhost/' );
+ $this->assertEquals(
+ 'http://localhost/',
+ $this->response->getHeader( 'Location' ),
+ 'Set header'
+ );
+
+ $this->response->header( 'Location: http://127.0.0.1/' );
+ $this->assertEquals(
+ 'http://127.0.0.1/',
+ $this->response->getHeader( 'Location' ),
+ 'Same header'
+ );
+
+ $this->response->header( 'Location: http://127.0.0.2/', false );
+ $this->assertEquals(
+ 'http://127.0.0.1/',
+ $this->response->getHeader( 'Location' ),
+ 'Same header with override disabled'
+ );
+
+ $this->response->header( 'Location: http://localhost/' );
+ $this->assertEquals(
+ 'http://localhost/',
+ $this->response->getHeader( 'LOCATION' ),
+ 'Get header case insensitive'
+ );
+ }
+
+ /**
+ * @covers FauxResponse::getStatusCode
+ */
+ public function testResponseCode() {
+ $this->response->header( 'HTTP/1.1 200' );
+ $this->assertEquals( 200, $this->response->getStatusCode(), 'Header with no message' );
+
+ $this->response->header( 'HTTP/1.x 201' );
+ $this->assertEquals(
+ 201,
+ $this->response->getStatusCode(),
+ 'Header with no message and protocol 1.x'
+ );
+
+ $this->response->header( 'HTTP/1.1 202 OK' );
+ $this->assertEquals( 202, $this->response->getStatusCode(), 'Normal header' );
+
+ $this->response->header( 'HTTP/1.x 203 OK' );
+ $this->assertEquals(
+ 203,
+ $this->response->getStatusCode(),
+ 'Normal header with no message and protocol 1.x'
+ );
+
+ $this->response->header( 'HTTP/1.x 204 OK', false, 205 );
+ $this->assertEquals(
+ 205,
+ $this->response->getStatusCode(),
+ 'Third parameter overrides the HTTP/... header'
+ );
+
+ $this->response->statusHeader( 210 );
+ $this->assertEquals(
+ 210,
+ $this->response->getStatusCode(),
+ 'Handle statusHeader method'
+ );
+
+ $this->response->header( 'Location: http://localhost/', false, 206 );
+ $this->assertEquals(
+ 206,
+ $this->response->getStatusCode(),
+ 'Third parameter with another header'
+ );
+ }
+}
--- /dev/null
+<?php
+
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * Test class for FormOptions initialization
+ * Ensure the FormOptions::add() does what we want it to do.
+ *
+ * Copyright © 2011, Antoine Musso
+ *
+ * @author Antoine Musso
+ */
+class FormOptionsInitializationTest extends \MediaWikiUnitTestCase {
+ /**
+ * @var FormOptions
+ */
+ protected $object;
+
+ /**
+ * A new fresh and empty FormOptions object to test initialization
+ * with.
+ */
+ protected function setUp() {
+ parent::setUp();
+ $this->object = TestingAccessWrapper::newFromObject( new FormOptions() );
+ }
+
+ /**
+ * @covers FormOptions::add
+ */
+ public function testAddStringOption() {
+ $this->object->add( 'foo', 'string value' );
+ $this->assertEquals(
+ [
+ 'foo' => [
+ 'default' => 'string value',
+ 'consumed' => false,
+ 'type' => FormOptions::STRING,
+ 'value' => null,
+ ]
+ ],
+ $this->object->options
+ );
+ }
+
+ /**
+ * @covers FormOptions::add
+ */
+ public function testAddIntegers() {
+ $this->object->add( 'one', 1 );
+ $this->object->add( 'negone', -1 );
+ $this->assertEquals(
+ [
+ 'negone' => [
+ 'default' => -1,
+ 'value' => null,
+ 'consumed' => false,
+ 'type' => FormOptions::INT,
+ ],
+ 'one' => [
+ 'default' => 1,
+ 'value' => null,
+ 'consumed' => false,
+ 'type' => FormOptions::INT,
+ ]
+ ],
+ $this->object->options
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * This file host two test case classes for the MediaWiki FormOptions class:
+ * - FormOptionsInitializationTest : tests initialization of the class.
+ * - FormOptionsTest : tests methods an on instance
+ *
+ * The split let us take advantage of setting up a fixture for the methods
+ * tests.
+ */
+
+/**
+ * Test class for FormOptions methods.
+ *
+ * Copyright © 2011, Antoine Musso
+ *
+ * @author Antoine Musso
+ */
+class FormOptionsTest extends \MediaWikiUnitTestCase {
+ /**
+ * @var FormOptions
+ */
+ protected $object;
+
+ /**
+ * Instanciates a FormOptions object to play with.
+ * FormOptions::add() is tested by the class FormOptionsInitializationTest
+ * so we assume the function is well tested already an use it to create
+ * the fixture.
+ */
+ protected function setUp() {
+ parent::setUp();
+ $this->object = new FormOptions;
+ $this->object->add( 'string1', 'string one' );
+ $this->object->add( 'string2', 'string two' );
+ $this->object->add( 'integer', 0 );
+ $this->object->add( 'float', 0.0 );
+ $this->object->add( 'intnull', 0, FormOptions::INTNULL );
+ }
+
+ /** Helpers for testGuessType() */
+ /* @{ */
+ private function assertGuessBoolean( $data ) {
+ $this->guess( FormOptions::BOOL, $data );
+ }
+
+ private function assertGuessInt( $data ) {
+ $this->guess( FormOptions::INT, $data );
+ }
+
+ private function assertGuessFloat( $data ) {
+ $this->guess( FormOptions::FLOAT, $data );
+ }
+
+ private function assertGuessString( $data ) {
+ $this->guess( FormOptions::STRING, $data );
+ }
+
+ private function assertGuessArray( $data ) {
+ $this->guess( FormOptions::ARR, $data );
+ }
+
+ /** Generic helper */
+ private function guess( $expected, $data ) {
+ $this->assertEquals(
+ $expected,
+ FormOptions::guessType( $data )
+ );
+ }
+
+ /* @} */
+
+ /**
+ * Reuse helpers above assertGuessBoolean assertGuessInt assertGuessString
+ * @covers FormOptions::guessType
+ */
+ public function testGuessTypeDetection() {
+ $this->assertGuessBoolean( true );
+ $this->assertGuessBoolean( false );
+
+ $this->assertGuessInt( 0 );
+ $this->assertGuessInt( -5 );
+ $this->assertGuessInt( 5 );
+ $this->assertGuessInt( 0x0F );
+
+ $this->assertGuessFloat( 0.0 );
+ $this->assertGuessFloat( 1.5 );
+ $this->assertGuessFloat( 1e3 );
+
+ $this->assertGuessString( 'true' );
+ $this->assertGuessString( 'false' );
+ $this->assertGuessString( '5' );
+ $this->assertGuessString( '0' );
+ $this->assertGuessString( '1.5' );
+
+ $this->assertGuessArray( [ 'foo' ] );
+ }
+
+ /**
+ * @expectedException MWException
+ * @covers FormOptions::guessType
+ */
+ public function testGuessTypeOnNullThrowException() {
+ $this->object->guessType( null );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @covers Licenses
+ */
+class LicensesTest extends \MediaWikiUnitTestCase {
+
+ public function testLicenses() {
+ $str = "
+* Free licenses:
+** GFDL|Debian disagrees
+";
+
+ $lc = new Licenses( [
+ 'fieldname' => 'FooField',
+ 'type' => 'select',
+ 'section' => 'description',
+ 'id' => 'wpLicense',
+ 'label' => 'A label text', # Note can't test label-message because $wgOut is not defined
+ 'name' => 'AnotherName',
+ 'licenses' => $str,
+ ] );
+ $this->assertThat( $lc, $this->isInstanceOf( Licenses::class ) );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Rest;
+
+use MediaWiki\Rest\HeaderContainer;
+
+/**
+ * @covers \MediaWiki\Rest\HeaderContainer
+ */
+class HeaderContainerTest extends \MediaWikiUnitTestCase {
+ public static function provideSetHeader() {
+ return [
+ 'simple' => [
+ [
+ [ 'Test', 'foo' ]
+ ],
+ [ 'Test' => [ 'foo' ] ],
+ [ 'Test' => 'foo' ]
+ ],
+ 'replace' => [
+ [
+ [ 'Test', 'foo' ],
+ [ 'Test', 'bar' ],
+ ],
+ [ 'Test' => [ 'bar' ] ],
+ [ 'Test' => 'bar' ],
+ ],
+ 'array value' => [
+ [
+ [ 'Test', [ '1', '2' ] ],
+ [ 'Test', [ '3', '4' ] ],
+ ],
+ [ 'Test' => [ '3', '4' ] ],
+ [ 'Test' => '3, 4' ]
+ ],
+ 'preserve most recent case' => [
+ [
+ [ 'test', 'foo' ],
+ [ 'tesT', 'bar' ],
+ ],
+ [ 'tesT' => [ 'bar' ] ],
+ [ 'tesT' => 'bar' ]
+ ],
+ 'empty' => [ [], [], [] ],
+ ];
+ }
+
+ /** @dataProvider provideSetHeader */
+ public function testSetHeader( $setOps, $headers, $lines ) {
+ $hc = new HeaderContainer;
+ foreach ( $setOps as list( $name, $value ) ) {
+ $hc->setHeader( $name, $value );
+ }
+ $this->assertSame( $headers, $hc->getHeaders() );
+ $this->assertSame( $lines, $hc->getHeaderLines() );
+ }
+
+ public static function provideAddHeader() {
+ return [
+ 'simple' => [
+ [
+ [ 'Test', 'foo' ]
+ ],
+ [ 'Test' => [ 'foo' ] ],
+ [ 'Test' => 'foo' ]
+ ],
+ 'add' => [
+ [
+ [ 'Test', 'foo' ],
+ [ 'Test', 'bar' ],
+ ],
+ [ 'Test' => [ 'foo', 'bar' ] ],
+ [ 'Test' => 'foo, bar' ],
+ ],
+ 'array value' => [
+ [
+ [ 'Test', [ '1', '2' ] ],
+ [ 'Test', [ '3', '4' ] ],
+ ],
+ [ 'Test' => [ '1', '2', '3', '4' ] ],
+ [ 'Test' => '1, 2, 3, 4' ]
+ ],
+ 'preserve original case' => [
+ [
+ [ 'Test', 'foo' ],
+ [ 'tesT', 'bar' ],
+ ],
+ [ 'Test' => [ 'foo', 'bar' ] ],
+ [ 'Test' => 'foo, bar' ]
+ ],
+ ];
+ }
+
+ /** @dataProvider provideAddHeader */
+ public function testAddHeader( $addOps, $headers, $lines ) {
+ $hc = new HeaderContainer;
+ foreach ( $addOps as list( $name, $value ) ) {
+ $hc->addHeader( $name, $value );
+ }
+ $this->assertSame( $headers, $hc->getHeaders() );
+ $this->assertSame( $lines, $hc->getHeaderLines() );
+ }
+
+ public static function provideRemoveHeader() {
+ return [
+ 'simple' => [
+ [ [ 'Test', 'foo' ] ],
+ [ 'Test' ],
+ [],
+ []
+ ],
+ 'case mismatch' => [
+ [ [ 'Test', 'foo' ] ],
+ [ 'tesT' ],
+ [],
+ []
+ ],
+ 'remove nonexistent' => [
+ [ [ 'A', '1' ] ],
+ [ 'B' ],
+ [ 'A' => [ '1' ] ],
+ [ 'A' => '1' ]
+ ],
+ ];
+ }
+
+ /** @dataProvider provideRemoveHeader */
+ public function testRemoveHeader( $addOps, $removeOps, $headers, $lines ) {
+ $hc = new HeaderContainer;
+ foreach ( $addOps as list( $name, $value ) ) {
+ $hc->addHeader( $name, $value );
+ }
+ foreach ( $removeOps as $name ) {
+ $hc->removeHeader( $name );
+ }
+ $this->assertSame( $headers, $hc->getHeaders() );
+ $this->assertSame( $lines, $hc->getHeaderLines() );
+ }
+
+ public function testHasHeader() {
+ $hc = new HeaderContainer;
+ $hc->addHeader( 'A', '1' );
+ $hc->addHeader( 'B', '2' );
+ $hc->addHeader( 'C', '3' );
+ $hc->removeHeader( 'B' );
+ $hc->removeHeader( 'c' );
+ $this->assertTrue( $hc->hasHeader( 'A' ) );
+ $this->assertTrue( $hc->hasHeader( 'a' ) );
+ $this->assertFalse( $hc->hasHeader( 'B' ) );
+ $this->assertFalse( $hc->hasHeader( 'c' ) );
+ $this->assertFalse( $hc->hasHeader( 'C' ) );
+ }
+
+ public function testGetRawHeaderLines() {
+ $hc = new HeaderContainer;
+ $hc->addHeader( 'A', '1' );
+ $hc->addHeader( 'a', '2' );
+ $hc->addHeader( 'b', '3' );
+ $hc->addHeader( 'Set-Cookie', 'x' );
+ $hc->addHeader( 'SET-cookie', 'y' );
+ $this->assertSame(
+ [
+ 'A: 1, 2',
+ 'b: 3',
+ 'Set-Cookie: x',
+ 'Set-Cookie: y',
+ ],
+ $hc->getRawHeaderLines()
+ );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Rest\PathTemplateMatcher;
+
+use MediaWiki\Rest\PathTemplateMatcher\PathConflict;
+use MediaWiki\Rest\PathTemplateMatcher\PathMatcher;
+
+/**
+ * @covers \MediaWiki\Rest\PathTemplateMatcher\PathMatcher
+ * @covers \MediaWiki\Rest\PathTemplateMatcher\PathConflict
+ */
+class PathMatcherTest extends \MediaWikiUnitTestCase {
+ private static $normalRoutes = [
+ '/a/b',
+ '/b/{x}',
+ '/c/{x}/d',
+ '/c/{x}/e',
+ '/c/{x}/{y}/d',
+ ];
+
+ public static function provideConflictingRoutes() {
+ return [
+ [ '/a/b', 0, '/a/b' ],
+ [ '/a/{x}', 0, '/a/b' ],
+ [ '/{x}/c', 1, '/b/{x}' ],
+ [ '/b/a', 1, '/b/{x}' ],
+ [ '/b/{x}', 1, '/b/{x}' ],
+ [ '/{x}/{y}/d', 2, '/c/{x}/d' ],
+ ];
+ }
+
+ public static function provideMatch() {
+ return [
+ [ '', false ],
+ [ '/a/b', [ 'params' => [], 'userData' => 0 ] ],
+ [ '/b', false ],
+ [ '/b/1', [ 'params' => [ 'x' => '1' ], 'userData' => 1 ] ],
+ [ '/c/1/d', [ 'params' => [ 'x' => '1' ], 'userData' => 2 ] ],
+ [ '/c/1/e', [ 'params' => [ 'x' => '1' ], 'userData' => 3 ] ],
+ [ '/c/000/e', [ 'params' => [ 'x' => '000' ], 'userData' => 3 ] ],
+ [ '/c/1/f', false ],
+ [ '/c//e', [ 'params' => [ 'x' => '' ], 'userData' => 3 ] ],
+ [ '/c///e', false ],
+ ];
+ }
+
+ public function createNormalRouter() {
+ $pm = new PathMatcher;
+ foreach ( self::$normalRoutes as $i => $route ) {
+ $pm->add( $route, $i );
+ }
+ return $pm;
+ }
+
+ /** @dataProvider provideConflictingRoutes */
+ public function testAddConflict( $attempt, $expectedUserData, $expectedTemplate ) {
+ $pm = $this->createNormalRouter();
+ $actualTemplate = null;
+ $actualUserData = null;
+ try {
+ $pm->add( $attempt, 'conflict' );
+ } catch ( PathConflict $pc ) {
+ $actualTemplate = $pc->existingTemplate;
+ $actualUserData = $pc->existingUserData;
+ }
+ $this->assertSame( $expectedUserData, $actualUserData );
+ $this->assertSame( $expectedTemplate, $actualTemplate );
+ }
+
+ /** @dataProvider provideMatch */
+ public function testMatch( $path, $expectedResult ) {
+ $pm = $this->createNormalRouter();
+ $result = $pm->match( $path );
+ $this->assertSame( $expectedResult, $result );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Rest;
+
+use MediaWiki\Rest\StringStream;
+
+/** @covers \MediaWiki\Rest\StringStream */
+class StringStreamTest extends \MediaWikiUnitTestCase {
+ public static function provideSeekGetContents() {
+ return [
+ [ 'abcde', 0, SEEK_SET, 'abcde' ],
+ [ 'abcde', 1, SEEK_SET, 'bcde' ],
+ [ 'abcde', 5, SEEK_SET, '' ],
+ [ 'abcde', 1, SEEK_CUR, 'cde' ],
+ [ 'abcde', 0, SEEK_END, '' ],
+ ];
+ }
+
+ /** @dataProvider provideSeekGetContents */
+ public function testCopyToStream( $input, $offset, $whence, $expected ) {
+ $ss = new StringStream;
+ $ss->write( $input );
+ $ss->seek( 1 );
+ $ss->seek( $offset, $whence );
+ $destStream = fopen( 'php://memory', 'w+' );
+ $ss->copyToStream( $destStream );
+ fseek( $destStream, 0 );
+ $result = stream_get_contents( $destStream );
+ $this->assertSame( $expected, $result );
+ }
+
+ public function testGetSize() {
+ $ss = new StringStream;
+ $this->assertSame( 0, $ss->getSize() );
+ $ss->write( "hello" );
+ $this->assertSame( 5, $ss->getSize() );
+ $ss->rewind();
+ $this->assertSame( 5, $ss->getSize() );
+ }
+
+ public function testTell() {
+ $ss = new StringStream;
+ $this->assertSame( $ss->tell(), 0 );
+ $ss->write( "abc" );
+ $this->assertSame( $ss->tell(), 3 );
+ $ss->seek( 0 );
+ $ss->read( 1 );
+ $this->assertSame( $ss->tell(), 1 );
+ }
+
+ public function testEof() {
+ $ss = new StringStream( 'abc' );
+ $this->assertFalse( $ss->eof() );
+ $ss->read( 1 );
+ $this->assertFalse( $ss->eof() );
+ $ss->read( 1 );
+ $this->assertFalse( $ss->eof() );
+ $ss->read( 1 );
+ $this->assertTrue( $ss->eof() );
+ $ss->rewind();
+ $this->assertFalse( $ss->eof() );
+ }
+
+ public function testIsSeekable() {
+ $ss = new StringStream;
+ $this->assertTrue( $ss->isSeekable() );
+ }
+
+ public function testIsReadable() {
+ $ss = new StringStream;
+ $this->assertTrue( $ss->isReadable() );
+ }
+
+ public function testIsWritable() {
+ $ss = new StringStream;
+ $this->assertTrue( $ss->isWritable() );
+ }
+
+ public function testSeekWrite() {
+ $ss = new StringStream;
+ $this->assertSame( '', (string)$ss );
+ $ss->write( 'a' );
+ $this->assertSame( 'a', (string)$ss );
+ $ss->write( 'b' );
+ $this->assertSame( 'ab', (string)$ss );
+ $ss->seek( 1 );
+ $ss->write( 'c' );
+ $this->assertSame( 'ac', (string)$ss );
+ }
+
+ /** @dataProvider provideSeekGetContents */
+ public function testSeekGetContents( $input, $offset, $whence, $expected ) {
+ $ss = new StringStream( $input );
+ $ss->seek( 1 );
+ $ss->seek( $offset, $whence );
+ $this->assertSame( $expected, $ss->getContents() );
+ }
+
+ public static function provideSeekRead() {
+ return [
+ [ 'abcde', 0, SEEK_SET, 1, 'a' ],
+ [ 'abcde', 0, SEEK_SET, 2, 'ab' ],
+ [ 'abcde', 4, SEEK_SET, 2, 'e' ],
+ [ 'abcde', 5, SEEK_SET, 1, '' ],
+ [ 'abcde', 1, SEEK_CUR, 1, 'c' ],
+ [ 'abcde', 0, SEEK_END, 1, '' ],
+ [ 'abcde', -1, SEEK_END, 1, 'e' ],
+ ];
+ }
+
+ /** @dataProvider provideSeekRead */
+ public function testSeekRead( $input, $offset, $whence, $length, $expected ) {
+ $ss = new StringStream( $input );
+ $ss->seek( 1 );
+ $ss->seek( $offset, $whence );
+ $this->assertSame( $expected, $ss->read( $length ) );
+ }
+
+ /** @expectedException \InvalidArgumentException */
+ public function testReadBeyondEnd() {
+ $ss = new StringStream( 'abc' );
+ $ss->seek( 1, SEEK_END );
+ }
+
+ /** @expectedException \InvalidArgumentException */
+ public function testReadBeforeStart() {
+ $ss = new StringStream( 'abc' );
+ $ss->seek( -1 );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Revision;
+
+use MediaWiki\Revision\FallbackSlotRoleHandler;
+use Title;
+
+/**
+ * @covers \MediaWiki\Revision\FallbackSlotRoleHandler
+ */
+class FallbackSlotRoleHandlerTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @return Title
+ */
+ private function makeBlankTitleObject() {
+ return $this->createMock( Title::class );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::__construct
+ * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::getRole()
+ * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::getNameMessageKey()
+ * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::getDefaultModel()
+ * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::getOutputLayoutHints()
+ */
+ public function testConstruction() {
+ $handler = new FallbackSlotRoleHandler( 'foo' );
+ $this->assertSame( 'foo', $handler->getRole() );
+ $this->assertSame( 'slot-name-foo', $handler->getNameMessageKey() );
+
+ $title = $this->makeBlankTitleObject();
+ $this->assertSame( CONTENT_MODEL_TEXT, $handler->getDefaultModel( $title ) );
+
+ $hints = $handler->getOutputLayoutHints();
+ $this->assertArrayHasKey( 'display', $hints );
+ $this->assertArrayHasKey( 'region', $hints );
+ $this->assertArrayHasKey( 'placement', $hints );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::isAllowedModel()
+ */
+ public function testIsAllowedModel() {
+ $handler = new FallbackSlotRoleHandler( 'foo', 'FooModel' );
+
+ // For the fallback handler, no models are allowed
+ $title = $this->makeBlankTitleObject();
+ $this->assertFalse( $handler->isAllowedModel( 'FooModel', $title ) );
+ $this->assertFalse( $handler->isAllowedModel( 'QuaxModel', $title ) );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\SlotRoleHandler::isAllowedModel()
+ */
+ public function testIsAllowedOn() {
+ $handler = new FallbackSlotRoleHandler( 'foo', 'FooModel' );
+
+ $title = $this->makeBlankTitleObject();
+ $this->assertFalse( $handler->isAllowedOn( $title ) );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\FallbackSlotRoleHandler::supportsArticleCount()
+ */
+ public function testSupportsArticleCount() {
+ $handler = new FallbackSlotRoleHandler( 'foo', 'FooModel' );
+
+ $this->assertFalse( $handler->supportsArticleCount() );
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Revision;
+
+use MediaWiki\Revision\SlotRoleHandler;
+use Title;
+
+/**
+ * @covers \MediaWiki\Revision\SlotRoleHandler
+ */
+class SlotRoleHandlerTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @return Title
+ */
+ private function makeBlankTitleObject() {
+ return $this->createMock( Title::class );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\SlotRoleHandler::__construct
+ * @covers \MediaWiki\Revision\SlotRoleHandler::getRole()
+ * @covers \MediaWiki\Revision\SlotRoleHandler::getNameMessageKey()
+ * @covers \MediaWiki\Revision\SlotRoleHandler::getDefaultModel()
+ * @covers \MediaWiki\Revision\SlotRoleHandler::getOutputLayoutHints()
+ */
+ public function testConstruction() {
+ $handler = new SlotRoleHandler( 'foo', 'FooModel', [ 'frob' => 'niz' ] );
+ $this->assertSame( 'foo', $handler->getRole() );
+ $this->assertSame( 'slot-name-foo', $handler->getNameMessageKey() );
+
+ $title = $this->makeBlankTitleObject();
+ $this->assertSame( 'FooModel', $handler->getDefaultModel( $title ) );
+
+ $hints = $handler->getOutputLayoutHints();
+ $this->assertArrayHasKey( 'frob', $hints );
+ $this->assertSame( 'niz', $hints['frob'] );
+
+ $this->assertArrayHasKey( 'display', $hints );
+ $this->assertArrayHasKey( 'region', $hints );
+ $this->assertArrayHasKey( 'placement', $hints );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\SlotRoleHandler::isAllowedModel()
+ */
+ public function testIsAllowedModel() {
+ $handler = new SlotRoleHandler( 'foo', 'FooModel' );
+
+ $title = $this->makeBlankTitleObject();
+ $this->assertTrue( $handler->isAllowedModel( 'FooModel', $title ) );
+ $this->assertFalse( $handler->isAllowedModel( 'QuaxModel', $title ) );
+ }
+
+ /**
+ * @covers \MediaWiki\Revision\SlotRoleHandler::supportsArticleCount()
+ */
+ public function testSupportsArticleCount() {
+ $handler = new SlotRoleHandler( 'foo', 'FooModel' );
+
+ $this->assertFalse( $handler->supportsArticleCount() );
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @coversNothing
+ */
+class ServiceWiringTest extends \MediaWikiUnitTestCase {
+ public function testServicesAreSorted() {
+ global $IP;
+ $services = array_keys( require "$IP/includes/ServiceWiring.php" );
+ $sortedServices = $services;
+ natcasesort( $sortedServices );
+
+ $this->assertSame( $sortedServices, $services,
+ 'Please keep services sorted alphabetically' );
+ }
+}
--- /dev/null
+<?php
+
+class SiteConfigurationTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @var SiteConfiguration
+ */
+ protected $mConf;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->mConf = new SiteConfiguration;
+
+ $this->mConf->suffixes = [ 'wikipedia' => 'wiki' ];
+ $this->mConf->wikis = [ 'enwiki', 'dewiki', 'frwiki' ];
+ $this->mConf->settings = [
+ 'SimpleKey' => [
+ 'wiki' => 'wiki',
+ 'tag' => 'tag',
+ 'enwiki' => 'enwiki',
+ 'dewiki' => 'dewiki',
+ 'frwiki' => 'frwiki',
+ ],
+
+ 'Fallback' => [
+ 'default' => 'default',
+ 'wiki' => 'wiki',
+ 'tag' => 'tag',
+ 'frwiki' => 'frwiki',
+ 'null_wiki' => null,
+ ],
+
+ 'WithParams' => [
+ 'default' => '$lang $site $wiki',
+ ],
+
+ '+SomeGlobal' => [
+ 'wiki' => [
+ 'wiki' => 'wiki',
+ ],
+ 'tag' => [
+ 'tag' => 'tag',
+ ],
+ 'enwiki' => [
+ 'enwiki' => 'enwiki',
+ ],
+ 'dewiki' => [
+ 'dewiki' => 'dewiki',
+ ],
+ 'frwiki' => [
+ 'frwiki' => 'frwiki',
+ ],
+ ],
+
+ 'MergeIt' => [
+ '+wiki' => [
+ 'wiki' => 'wiki',
+ ],
+ '+tag' => [
+ 'tag' => 'tag',
+ ],
+ 'default' => [
+ 'default' => 'default',
+ ],
+ '+enwiki' => [
+ 'enwiki' => 'enwiki',
+ ],
+ '+dewiki' => [
+ 'dewiki' => 'dewiki',
+ ],
+ '+frwiki' => [
+ 'frwiki' => 'frwiki',
+ ],
+ ],
+ ];
+
+ $GLOBALS['SomeGlobal'] = [ 'SomeGlobal' => 'SomeGlobal' ];
+ }
+
+ /**
+ * This function is used as a callback within the tests below
+ */
+ public static function getSiteParamsCallback( $conf, $wiki ) {
+ $site = null;
+ $lang = null;
+ foreach ( $conf->suffixes as $suffix ) {
+ if ( substr( $wiki, -strlen( $suffix ) ) == $suffix ) {
+ $site = $suffix;
+ $lang = substr( $wiki, 0, -strlen( $suffix ) );
+ break;
+ }
+ }
+
+ return [
+ 'suffix' => $site,
+ 'lang' => $lang,
+ 'params' => [
+ 'lang' => $lang,
+ 'site' => $site,
+ 'wiki' => $wiki,
+ ],
+ 'tags' => [ 'tag' ],
+ ];
+ }
+
+ /**
+ * @covers SiteConfiguration::siteFromDB
+ */
+ public function testSiteFromDb() {
+ $this->assertEquals(
+ [ 'wikipedia', 'en' ],
+ $this->mConf->siteFromDB( 'enwiki' ),
+ 'siteFromDB()'
+ );
+ $this->assertEquals(
+ [ 'wikipedia', '' ],
+ $this->mConf->siteFromDB( 'wiki' ),
+ 'siteFromDB() on a suffix'
+ );
+ $this->assertEquals(
+ [ null, null ],
+ $this->mConf->siteFromDB( 'wikien' ),
+ 'siteFromDB() on a non-existing wiki'
+ );
+
+ $this->mConf->suffixes = [ 'wiki', '' ];
+ $this->assertEquals(
+ [ '', 'wikien' ],
+ $this->mConf->siteFromDB( 'wikien' ),
+ 'siteFromDB() on a non-existing wiki (2)'
+ );
+ }
+
+ /**
+ * @covers SiteConfiguration::getLocalDatabases
+ */
+ public function testGetLocalDatabases() {
+ $this->assertEquals(
+ [ 'enwiki', 'dewiki', 'frwiki' ],
+ $this->mConf->getLocalDatabases(),
+ 'getLocalDatabases()'
+ );
+ }
+
+ /**
+ * @covers SiteConfiguration::get
+ */
+ public function testGetConfVariables() {
+ // Simple
+ $this->assertEquals(
+ 'enwiki',
+ $this->mConf->get( 'SimpleKey', 'enwiki', 'wiki' ),
+ 'get(): simple setting on an existing wiki'
+ );
+ $this->assertEquals(
+ 'dewiki',
+ $this->mConf->get( 'SimpleKey', 'dewiki', 'wiki' ),
+ 'get(): simple setting on an existing wiki (2)'
+ );
+ $this->assertEquals(
+ 'frwiki',
+ $this->mConf->get( 'SimpleKey', 'frwiki', 'wiki' ),
+ 'get(): simple setting on an existing wiki (3)'
+ );
+ $this->assertEquals(
+ 'wiki',
+ $this->mConf->get( 'SimpleKey', 'wiki', 'wiki' ),
+ 'get(): simple setting on an suffix'
+ );
+ $this->assertEquals(
+ 'wiki',
+ $this->mConf->get( 'SimpleKey', 'eswiki', 'wiki' ),
+ 'get(): simple setting on an non-existing wiki'
+ );
+
+ // Fallback
+ $this->assertEquals(
+ 'wiki',
+ $this->mConf->get( 'Fallback', 'enwiki', 'wiki' ),
+ 'get(): fallback setting on an existing wiki'
+ );
+ $this->assertEquals(
+ 'tag',
+ $this->mConf->get( 'Fallback', 'dewiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): fallback setting on an existing wiki (with wiki tag)'
+ );
+ $this->assertEquals(
+ 'frwiki',
+ $this->mConf->get( 'Fallback', 'frwiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): no fallback if wiki has its own setting (matching tag)'
+ );
+ $this->assertSame(
+ // Potential regression test for T192855
+ null,
+ $this->mConf->get( 'Fallback', 'null_wiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): no fallback if wiki has its own setting (matching tag and uses null)'
+ );
+ $this->assertEquals(
+ 'wiki',
+ $this->mConf->get( 'Fallback', 'wiki', 'wiki' ),
+ 'get(): fallback setting on an suffix'
+ );
+ $this->assertEquals(
+ 'wiki',
+ $this->mConf->get( 'Fallback', 'wiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): fallback setting on an suffix (with wiki tag)'
+ );
+ $this->assertEquals(
+ 'wiki',
+ $this->mConf->get( 'Fallback', 'eswiki', 'wiki' ),
+ 'get(): fallback setting on an non-existing wiki'
+ );
+ $this->assertEquals(
+ 'tag',
+ $this->mConf->get( 'Fallback', 'eswiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): fallback setting on an non-existing wiki (with wiki tag)'
+ );
+
+ // Merging
+ $common = [ 'wiki' => 'wiki', 'default' => 'default' ];
+ $commonTag = [ 'tag' => 'tag', 'wiki' => 'wiki', 'default' => 'default' ];
+ $this->assertEquals(
+ [ 'enwiki' => 'enwiki' ] + $common,
+ $this->mConf->get( 'MergeIt', 'enwiki', 'wiki' ),
+ 'get(): merging setting on an existing wiki'
+ );
+ $this->assertEquals(
+ [ 'enwiki' => 'enwiki' ] + $commonTag,
+ $this->mConf->get( 'MergeIt', 'enwiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): merging setting on an existing wiki (with tag)'
+ );
+ $this->assertEquals(
+ [ 'dewiki' => 'dewiki' ] + $common,
+ $this->mConf->get( 'MergeIt', 'dewiki', 'wiki' ),
+ 'get(): merging setting on an existing wiki (2)'
+ );
+ $this->assertEquals(
+ [ 'dewiki' => 'dewiki' ] + $commonTag,
+ $this->mConf->get( 'MergeIt', 'dewiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): merging setting on an existing wiki (2) (with tag)'
+ );
+ $this->assertEquals(
+ [ 'frwiki' => 'frwiki' ] + $common,
+ $this->mConf->get( 'MergeIt', 'frwiki', 'wiki' ),
+ 'get(): merging setting on an existing wiki (3)'
+ );
+ $this->assertEquals(
+ [ 'frwiki' => 'frwiki' ] + $commonTag,
+ $this->mConf->get( 'MergeIt', 'frwiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): merging setting on an existing wiki (3) (with tag)'
+ );
+ $this->assertEquals(
+ [ 'wiki' => 'wiki' ] + $common,
+ $this->mConf->get( 'MergeIt', 'wiki', 'wiki' ),
+ 'get(): merging setting on an suffix'
+ );
+ $this->assertEquals(
+ [ 'wiki' => 'wiki' ] + $commonTag,
+ $this->mConf->get( 'MergeIt', 'wiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): merging setting on an suffix (with tag)'
+ );
+ $this->assertEquals(
+ $common,
+ $this->mConf->get( 'MergeIt', 'eswiki', 'wiki' ),
+ 'get(): merging setting on an non-existing wiki'
+ );
+ $this->assertEquals(
+ $commonTag,
+ $this->mConf->get( 'MergeIt', 'eswiki', 'wiki', [], [ 'tag' ] ),
+ 'get(): merging setting on an non-existing wiki (with tag)'
+ );
+ }
+
+ /**
+ * @covers SiteConfiguration::siteFromDB
+ */
+ public function testSiteFromDbWithCallback() {
+ $this->mConf->siteParamsCallback = 'SiteConfigurationTest::getSiteParamsCallback';
+
+ $this->assertEquals(
+ [ 'wiki', 'en' ],
+ $this->mConf->siteFromDB( 'enwiki' ),
+ 'siteFromDB() with callback'
+ );
+ $this->assertEquals(
+ [ 'wiki', '' ],
+ $this->mConf->siteFromDB( 'wiki' ),
+ 'siteFromDB() with callback on a suffix'
+ );
+ $this->assertEquals(
+ [ null, null ],
+ $this->mConf->siteFromDB( 'wikien' ),
+ 'siteFromDB() with callback on a non-existing wiki'
+ );
+ }
+
+ /**
+ * @covers SiteConfiguration::get
+ */
+ public function testParameterReplacement() {
+ $this->mConf->siteParamsCallback = 'SiteConfigurationTest::getSiteParamsCallback';
+
+ $this->assertEquals(
+ 'en wiki enwiki',
+ $this->mConf->get( 'WithParams', 'enwiki', 'wiki' ),
+ 'get(): parameter replacement on an existing wiki'
+ );
+ $this->assertEquals(
+ 'de wiki dewiki',
+ $this->mConf->get( 'WithParams', 'dewiki', 'wiki' ),
+ 'get(): parameter replacement on an existing wiki (2)'
+ );
+ $this->assertEquals(
+ 'fr wiki frwiki',
+ $this->mConf->get( 'WithParams', 'frwiki', 'wiki' ),
+ 'get(): parameter replacement on an existing wiki (3)'
+ );
+ $this->assertEquals(
+ ' wiki wiki',
+ $this->mConf->get( 'WithParams', 'wiki', 'wiki' ),
+ 'get(): parameter replacement on an suffix'
+ );
+ $this->assertEquals(
+ 'es wiki eswiki',
+ $this->mConf->get( 'WithParams', 'eswiki', 'wiki' ),
+ 'get(): parameter replacement on an non-existing wiki'
+ );
+ }
+
+ /**
+ * @covers SiteConfiguration::getAll
+ */
+ public function testGetAllGlobals() {
+ $this->mConf->siteParamsCallback = 'SiteConfigurationTest::getSiteParamsCallback';
+
+ $getall = [
+ 'SimpleKey' => 'enwiki',
+ 'Fallback' => 'tag',
+ 'WithParams' => 'en wiki enwiki',
+ 'SomeGlobal' => [ 'enwiki' => 'enwiki' ] + $GLOBALS['SomeGlobal'],
+ 'MergeIt' => [
+ 'enwiki' => 'enwiki',
+ 'tag' => 'tag',
+ 'wiki' => 'wiki',
+ 'default' => 'default'
+ ],
+ ];
+ $this->assertEquals( $getall, $this->mConf->getAll( 'enwiki' ), 'getAll()' );
+
+ $this->mConf->extractAllGlobals( 'enwiki', 'wiki' );
+
+ $this->assertEquals(
+ $getall['SimpleKey'],
+ $GLOBALS['SimpleKey'],
+ 'extractAllGlobals(): simple setting'
+ );
+ $this->assertEquals(
+ $getall['Fallback'],
+ $GLOBALS['Fallback'],
+ 'extractAllGlobals(): fallback setting'
+ );
+ $this->assertEquals(
+ $getall['WithParams'],
+ $GLOBALS['WithParams'],
+ 'extractAllGlobals(): parameter replacement'
+ );
+ $this->assertEquals(
+ $getall['SomeGlobal'],
+ $GLOBALS['SomeGlobal'],
+ 'extractAllGlobals(): merging with global'
+ );
+ $this->assertEquals(
+ $getall['MergeIt'],
+ $GLOBALS['MergeIt'],
+ 'extractAllGlobals(): merging setting'
+ );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Edit;
+
+use ParserOutput;
+
+/**
+ * @covers \MediaWiki\Edit\PreparedEdit
+ */
+class PreparedEditTest extends \MediaWikiUnitTestCase {
+ function testCallback() {
+ $output = new ParserOutput();
+ $edit = new PreparedEdit();
+ $edit->parserOutputCallback = function () {
+ return new ParserOutput();
+ };
+
+ $this->assertEquals( $output, $edit->getOutput() );
+ $this->assertEquals( $output, $edit->output );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group Xml
+ */
+class XmlSelectTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @var XmlSelect
+ */
+ protected $select;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->select = new XmlSelect();
+ }
+
+ protected function tearDown() {
+ parent::tearDown();
+ $this->select = null;
+ }
+
+ /**
+ * @covers XmlSelect::__construct
+ */
+ public function testConstructWithoutParameters() {
+ $this->assertEquals( '<select></select>', $this->select->getHTML() );
+ }
+
+ /**
+ * Parameters are $name (false), $id (false), $default (false)
+ * @dataProvider provideConstructionParameters
+ * @covers XmlSelect::__construct
+ */
+ public function testConstructParameters( $name, $id, $default, $expected ) {
+ $this->select = new XmlSelect( $name, $id, $default );
+ $this->assertEquals( $expected, $this->select->getHTML() );
+ }
+
+ /**
+ * Provide parameters for testConstructParameters() which use three
+ * parameters:
+ * - $name (default: false)
+ * - $id (default: false)
+ * - $default (default: false)
+ * Provides a fourth parameters representing the expected HTML output
+ */
+ public static function provideConstructionParameters() {
+ return [
+ /**
+ * Values are set following a 3-bit Gray code where two successive
+ * values differ by only one value.
+ * See https://en.wikipedia.org/wiki/Gray_code
+ */
+ # $name $id $default
+ [ false, false, false, '<select></select>' ],
+ [ false, false, 'foo', '<select></select>' ],
+ [ false, 'id', 'foo', '<select id="id"></select>' ],
+ [ false, 'id', false, '<select id="id"></select>' ],
+ [ 'name', 'id', false, '<select name="name" id="id"></select>' ],
+ [ 'name', 'id', 'foo', '<select name="name" id="id"></select>' ],
+ [ 'name', false, 'foo', '<select name="name"></select>' ],
+ [ 'name', false, false, '<select name="name"></select>' ],
+ ];
+ }
+
+ /**
+ * @covers XmlSelect::addOption
+ */
+ public function testAddOption() {
+ $this->select->addOption( 'foo' );
+ $this->assertEquals(
+ '<select><option value="foo">foo</option></select>',
+ $this->select->getHTML()
+ );
+ }
+
+ /**
+ * @covers XmlSelect::addOption
+ */
+ public function testAddOptionWithDefault() {
+ $this->select->addOption( 'foo', true );
+ $this->assertEquals(
+ '<select><option value="1">foo</option></select>',
+ $this->select->getHTML()
+ );
+ }
+
+ /**
+ * @covers XmlSelect::addOption
+ */
+ public function testAddOptionWithFalse() {
+ $this->select->addOption( 'foo', false );
+ $this->assertEquals(
+ '<select><option value="foo">foo</option></select>',
+ $this->select->getHTML()
+ );
+ }
+
+ /**
+ * @covers XmlSelect::addOption
+ */
+ public function testAddOptionWithValueZero() {
+ $this->select->addOption( 'foo', 0 );
+ $this->assertEquals(
+ '<select><option value="0">foo</option></select>',
+ $this->select->getHTML()
+ );
+ }
+
+ /**
+ * @covers XmlSelect::setDefault
+ */
+ public function testSetDefault() {
+ $this->select->setDefault( 'bar1' );
+ $this->select->addOption( 'foo1' );
+ $this->select->addOption( 'bar1' );
+ $this->select->addOption( 'foo2' );
+ $this->assertEquals(
+ '<select><option value="foo1">foo1</option>' . "\n" .
+ '<option value="bar1" selected="">bar1</option>' . "\n" .
+ '<option value="foo2">foo2</option></select>', $this->select->getHTML() );
+ }
+
+ /**
+ * Adding default later on should set the correct selection or
+ * raise an exception.
+ * To handle this, we need to render the options in getHtml()
+ * @covers XmlSelect::setDefault
+ */
+ public function testSetDefaultAfterAddingOptions() {
+ $this->select->addOption( 'foo1' );
+ $this->select->addOption( 'bar1' );
+ $this->select->addOption( 'foo2' );
+ $this->select->setDefault( 'bar1' ); # setting default after adding options
+ $this->assertEquals(
+ '<select><option value="foo1">foo1</option>' . "\n" .
+ '<option value="bar1" selected="">bar1</option>' . "\n" .
+ '<option value="foo2">foo2</option></select>', $this->select->getHTML() );
+ }
+
+ /**
+ * @covers XmlSelect::setAttribute
+ * @covers XmlSelect::getAttribute
+ */
+ public function testGetAttributes() {
+ # create some attributes
+ $this->select->setAttribute( 'dummy', 0x777 );
+ $this->select->setAttribute( 'string', 'euro €' );
+ $this->select->setAttribute( 1911, 'razor' );
+
+ # verify we can retrieve them
+ $this->assertEquals(
+ $this->select->getAttribute( 'dummy' ),
+ 0x777
+ );
+ $this->assertEquals(
+ $this->select->getAttribute( 'string' ),
+ 'euro €'
+ );
+ $this->assertEquals(
+ $this->select->getAttribute( 1911 ),
+ 'razor'
+ );
+
+ # inexistent keys should give us 'null'
+ $this->assertEquals(
+ $this->select->getAttribute( 'I DO NOT EXIT' ),
+ null
+ );
+
+ # verify string / integer
+ $this->assertEquals(
+ $this->select->getAttribute( '1911' ),
+ 'razor'
+ );
+ $this->assertEquals(
+ $this->select->getAttribute( 'dummy' ),
+ 0x777
+ );
+ }
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers \MediaWiki\Auth\AuthenticationResponse
+ */
+class AuthenticationResponseTest extends \MediaWikiUnitTestCase {
+ /**
+ * @dataProvider provideConstructors
+ * @param string $constructor
+ * @param array $args
+ * @param array|Exception $expect
+ */
+ public function testConstructors( $constructor, $args, $expect ) {
+ if ( is_array( $expect ) ) {
+ $res = new AuthenticationResponse();
+ $res->messageType = 'warning';
+ foreach ( $expect as $field => $value ) {
+ $res->$field = $value;
+ }
+ $ret = call_user_func_array( "MediaWiki\\Auth\\AuthenticationResponse::$constructor", $args );
+ $this->assertEquals( $res, $ret );
+ } else {
+ try {
+ call_user_func_array( "MediaWiki\\Auth\\AuthenticationResponse::$constructor", $args );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \Exception $ex ) {
+ $this->assertEquals( $expect, $ex );
+ }
+ }
+ }
+
+ public function provideConstructors() {
+ $req = $this->getMockForAbstractClass( AuthenticationRequest::class );
+ $msg = new \Message( 'mainpage' );
+
+ return [
+ [ 'newPass', [], [
+ 'status' => AuthenticationResponse::PASS,
+ ] ],
+ [ 'newPass', [ 'name' ], [
+ 'status' => AuthenticationResponse::PASS,
+ 'username' => 'name',
+ ] ],
+ [ 'newPass', [ 'name', null ], [
+ 'status' => AuthenticationResponse::PASS,
+ 'username' => 'name',
+ ] ],
+
+ [ 'newFail', [ $msg ], [
+ 'status' => AuthenticationResponse::FAIL,
+ 'message' => $msg,
+ 'messageType' => 'error',
+ ] ],
+
+ [ 'newRestart', [ $msg ], [
+ 'status' => AuthenticationResponse::RESTART,
+ 'message' => $msg,
+ ] ],
+
+ [ 'newAbstain', [], [
+ 'status' => AuthenticationResponse::ABSTAIN,
+ ] ],
+
+ [ 'newUI', [ [ $req ], $msg ], [
+ 'status' => AuthenticationResponse::UI,
+ 'neededRequests' => [ $req ],
+ 'message' => $msg,
+ 'messageType' => 'warning',
+ ] ],
+
+ [ 'newUI', [ [ $req ], $msg, 'warning' ], [
+ 'status' => AuthenticationResponse::UI,
+ 'neededRequests' => [ $req ],
+ 'message' => $msg,
+ 'messageType' => 'warning',
+ ] ],
+
+ [ 'newUI', [ [ $req ], $msg, 'error' ], [
+ 'status' => AuthenticationResponse::UI,
+ 'neededRequests' => [ $req ],
+ 'message' => $msg,
+ 'messageType' => 'error',
+ ] ],
+ [ 'newUI', [ [], $msg ],
+ new \InvalidArgumentException( '$reqs may not be empty' )
+ ],
+
+ [ 'newRedirect', [ [ $req ], 'http://example.org/redir' ], [
+ 'status' => AuthenticationResponse::REDIRECT,
+ 'neededRequests' => [ $req ],
+ 'redirectTarget' => 'http://example.org/redir',
+ ] ],
+ [
+ 'newRedirect',
+ [ [ $req ], 'http://example.org/redir', [ 'foo' => 'bar' ] ],
+ [
+ 'status' => AuthenticationResponse::REDIRECT,
+ 'neededRequests' => [ $req ],
+ 'redirectTarget' => 'http://example.org/redir',
+ 'redirectApiData' => [ 'foo' => 'bar' ],
+ ]
+ ],
+ [ 'newRedirect', [ [], 'http://example.org/redir' ],
+ new \InvalidArgumentException( '$reqs may not be empty' )
+ ],
+ ];
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @covers ChangesListFilterGroup
+ */
+class ChangesListFilterGroupTest extends \MediaWikiUnitTestCase {
+ /**
+ * phpcs:disable Generic.Files.LineLength
+ * @expectedException MWException
+ * @expectedExceptionMessage Group names may not contain '_'. Use the naming convention: 'camelCase'
+ * phpcs:enable
+ */
+ public function testReservedCharacter() {
+ new MockChangesListFilterGroup(
+ [
+ 'type' => 'some_type',
+ 'name' => 'group_name',
+ 'priority' => 1,
+ 'filters' => [],
+ ]
+ );
+ }
+
+ public function testAutoPriorities() {
+ $group = new MockChangesListFilterGroup(
+ [
+ 'type' => 'some_type',
+ 'name' => 'groupName',
+ 'isFullCoverage' => true,
+ 'priority' => 1,
+ 'filters' => [
+ [ 'name' => 'hidefoo' ],
+ [ 'name' => 'hidebar' ],
+ [ 'name' => 'hidebaz' ],
+ ],
+ ]
+ );
+
+ $filters = $group->getFilters();
+ $this->assertEquals(
+ [
+ -2,
+ -3,
+ -4,
+ ],
+ array_map(
+ function ( $f ) {
+ return $f->getPriority();
+ },
+ array_values( $filters )
+ )
+ );
+ }
+
+ // Get without warnings
+ public function testGetFilter() {
+ $group = new MockChangesListFilterGroup(
+ [
+ 'type' => 'some_type',
+ 'name' => 'groupName',
+ 'isFullCoverage' => true,
+ 'priority' => 1,
+ 'filters' => [
+ [ 'name' => 'foo' ],
+ ],
+ ]
+ );
+
+ $this->assertEquals(
+ 'foo',
+ $group->getFilter( 'foo' )->getName()
+ );
+
+ $this->assertEquals(
+ null,
+ $group->getFilter( 'bar' )
+ );
+ }
+}
--- /dev/null
+<?php
+
+class HashConfigTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers HashConfig::newInstance
+ */
+ public function testNewInstance() {
+ $conf = HashConfig::newInstance();
+ $this->assertInstanceOf( HashConfig::class, $conf );
+ }
+
+ /**
+ * @covers HashConfig::__construct
+ */
+ public function testConstructor() {
+ $conf = new HashConfig();
+ $this->assertInstanceOf( HashConfig::class, $conf );
+
+ // Test passing arguments to the constructor
+ $conf2 = new HashConfig( [
+ 'one' => '1',
+ ] );
+ $this->assertEquals( '1', $conf2->get( 'one' ) );
+ }
+
+ /**
+ * @covers HashConfig::get
+ */
+ public function testGet() {
+ $conf = new HashConfig( [
+ 'one' => '1',
+ ] );
+ $this->assertEquals( '1', $conf->get( 'one' ) );
+ $this->setExpectedException( ConfigException::class, 'HashConfig::get: undefined option' );
+ $conf->get( 'two' );
+ }
+
+ /**
+ * @covers HashConfig::has
+ */
+ public function testHas() {
+ $conf = new HashConfig( [
+ 'one' => '1',
+ ] );
+ $this->assertTrue( $conf->has( 'one' ) );
+ $this->assertFalse( $conf->has( 'two' ) );
+ }
+
+ /**
+ * @covers HashConfig::set
+ */
+ public function testSet() {
+ $conf = new HashConfig( [
+ 'one' => '1',
+ ] );
+ $conf->set( 'two', '2' );
+ $this->assertEquals( '2', $conf->get( 'two' ) );
+ // Check that set overwrites
+ $conf->set( 'one', '3' );
+ $this->assertEquals( '3', $conf->get( 'one' ) );
+ }
+}
--- /dev/null
+<?php
+
+class MultiConfigTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * Tests that settings are fetched in the right order
+ *
+ * @covers MultiConfig::__construct
+ * @covers MultiConfig::get
+ */
+ public function testGet() {
+ $multi = new MultiConfig( [
+ new HashConfig( [ 'foo' => 'bar' ] ),
+ new HashConfig( [ 'foo' => 'baz', 'bar' => 'foo' ] ),
+ new HashConfig( [ 'bar' => 'baz' ] ),
+ ] );
+
+ $this->assertEquals( 'bar', $multi->get( 'foo' ) );
+ $this->assertEquals( 'foo', $multi->get( 'bar' ) );
+ $this->setExpectedException( ConfigException::class, 'MultiConfig::get: undefined option:' );
+ $multi->get( 'notset' );
+ }
+
+ /**
+ * @covers MultiConfig::has
+ */
+ public function testHas() {
+ $conf = new MultiConfig( [
+ new HashConfig( [ 'foo' => 'foo' ] ),
+ new HashConfig( [ 'something' => 'bleh' ] ),
+ new HashConfig( [ 'meh' => 'eh' ] ),
+ ] );
+
+ $this->assertTrue( $conf->has( 'foo' ) );
+ $this->assertTrue( $conf->has( 'something' ) );
+ $this->assertTrue( $conf->has( 'meh' ) );
+ $this->assertFalse( $conf->has( 'what' ) );
+ }
+}
--- /dev/null
+<?php
+
+use MediaWiki\Config\ServiceOptions;
+
+/**
+ * @coversDefaultClass \MediaWiki\Config\ServiceOptions
+ */
+class ServiceOptionsTest extends \MediaWikiUnitTestCase {
+ public static $testObj;
+
+ public static function setUpBeforeClass() {
+ parent::setUpBeforeClass();
+
+ self::$testObj = new stdclass();
+ }
+
+ /**
+ * @dataProvider provideConstructor
+ * @covers ::__construct
+ * @covers ::assertRequiredOptions
+ * @covers ::get
+ */
+ public function testConstructor( $expected, $keys, ...$sources ) {
+ $options = new ServiceOptions( $keys, ...$sources );
+
+ foreach ( $expected as $key => $val ) {
+ $this->assertSame( $val, $options->get( $key ) );
+ }
+
+ // This is lumped in the same test because there's no support for depending on a test that
+ // has a data provider.
+ $options->assertRequiredOptions( array_keys( $expected ) );
+
+ // Suppress warning if no assertions were run. This is expected for empty arguments.
+ $this->assertTrue( true );
+ }
+
+ public function provideConstructor() {
+ return [
+ 'No keys' => [ [], [], [ 'a' => 'aval' ] ],
+ 'Simple array source' => [
+ [ 'a' => 'aval', 'b' => 'bval' ],
+ [ 'a', 'b' ],
+ [ 'a' => 'aval', 'b' => 'bval', 'c' => 'cval' ],
+ ],
+ 'Simple HashConfig source' => [
+ [ 'a' => 'aval', 'b' => 'bval' ],
+ [ 'a', 'b' ],
+ new HashConfig( [ 'a' => 'aval', 'b' => 'bval', 'c' => 'cval' ] ),
+ ],
+ 'Three different sources' => [
+ [ 'a' => 'aval', 'b' => 'bval' ],
+ [ 'a', 'b' ],
+ [ 'z' => 'zval' ],
+ new HashConfig( [ 'a' => 'aval', 'c' => 'cval' ] ),
+ [ 'b' => 'bval', 'd' => 'dval' ],
+ ],
+ 'null key' => [
+ [ 'a' => null ],
+ [ 'a' ],
+ [ 'a' => null ],
+ ],
+ 'Numeric option name' => [
+ [ '0' => 'nothing' ],
+ [ '0' ],
+ [ '0' => 'nothing' ],
+ ],
+ 'Multiple sources for one key' => [
+ [ 'a' => 'winner' ],
+ [ 'a' ],
+ [ 'a' => 'winner' ],
+ [ 'a' => 'second place' ],
+ ],
+ 'Object value is passed by reference' => [
+ [ 'a' => self::$testObj ],
+ [ 'a' ],
+ [ 'a' => self::$testObj ],
+ ],
+ ];
+ }
+
+ /**
+ * @covers ::__construct
+ */
+ public function testKeyNotFound() {
+ $this->setExpectedException( InvalidArgumentException::class,
+ 'Key "a" not found in input sources' );
+
+ new ServiceOptions( [ 'a' ], [ 'b' => 'bval' ], [ 'c' => 'cval' ] );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::assertRequiredOptions
+ */
+ public function testOutOfOrderAssertRequiredOptions() {
+ $options = new ServiceOptions( [ 'a', 'b' ], [ 'a' => '', 'b' => '' ] );
+ $options->assertRequiredOptions( [ 'b', 'a' ] );
+ $this->assertTrue( true, 'No exception thrown' );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::get
+ */
+ public function testGetUnrecognized() {
+ $this->setExpectedException( InvalidArgumentException::class,
+ 'Unrecognized option "b"' );
+
+ $options = new ServiceOptions( [ 'a' ], [ 'a' => '' ] );
+ $options->get( 'b' );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::assertRequiredOptions
+ */
+ public function testExtraKeys() {
+ $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
+ 'Precondition failed: Unsupported options passed: b, c!' );
+
+ $options = new ServiceOptions( [ 'a', 'b', 'c' ], [ 'a' => '', 'b' => '', 'c' => '' ] );
+ $options->assertRequiredOptions( [ 'a' ] );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::assertRequiredOptions
+ */
+ public function testMissingKeys() {
+ $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
+ 'Precondition failed: Required options missing: a, b!' );
+
+ $options = new ServiceOptions( [ 'c' ], [ 'c' => '' ] );
+ $options->assertRequiredOptions( [ 'a', 'b', 'c' ] );
+ }
+
+ /**
+ * @covers ::__construct
+ * @covers ::assertRequiredOptions
+ */
+ public function testExtraAndMissingKeys() {
+ $this->setExpectedException( Wikimedia\Assert\PreconditionException::class,
+ 'Precondition failed: Unsupported options passed: b! Required options missing: c!' );
+
+ $options = new ServiceOptions( [ 'a', 'b' ], [ 'a' => '', 'b' => '' ] );
+ $options->assertRequiredOptions( [ 'a', 'c' ] );
+ }
+}
--- /dev/null
+<?php
+
+class JsonContentHandlerTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers JsonContentHandler::makeEmptyContent
+ */
+ public function testMakeEmptyContent() {
+ $handler = new JsonContentHandler();
+ $content = $handler->makeEmptyContent();
+ $this->assertInstanceOf( JsonContent::class, $content );
+ $this->assertTrue( $content->isValid() );
+ }
+}
--- /dev/null
+<?php
+/**
+ * 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
+ */
+
+namespace MediaWiki\Logger;
+
+use Wikimedia\TestingAccessWrapper;
+
+class MonologSpiTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers MediaWiki\Logger\MonologSpi::mergeConfig
+ */
+ public function testMergeConfig() {
+ $base = [
+ 'loggers' => [
+ '@default' => [
+ 'processors' => [ 'constructor' ],
+ 'handlers' => [ 'constructor' ],
+ ],
+ ],
+ 'processors' => [
+ 'constructor' => [
+ 'class' => 'constructor',
+ ],
+ ],
+ 'handlers' => [
+ 'constructor' => [
+ 'class' => 'constructor',
+ 'formatter' => 'constructor',
+ ],
+ ],
+ 'formatters' => [
+ 'constructor' => [
+ 'class' => 'constructor',
+ ],
+ ],
+ ];
+
+ $fixture = new MonologSpi( $base );
+ $this->assertSame(
+ $base,
+ TestingAccessWrapper::newFromObject( $fixture )->config
+ );
+
+ $fixture->mergeConfig( [
+ 'loggers' => [
+ 'merged' => [
+ 'processors' => [ 'merged' ],
+ 'handlers' => [ 'merged' ],
+ ],
+ ],
+ 'processors' => [
+ 'merged' => [
+ 'class' => 'merged',
+ ],
+ ],
+ 'magic' => [
+ 'idkfa' => [ 'xyzzy' ],
+ ],
+ 'handlers' => [
+ 'merged' => [
+ 'class' => 'merged',
+ 'formatter' => 'merged',
+ ],
+ ],
+ 'formatters' => [
+ 'merged' => [
+ 'class' => 'merged',
+ ],
+ ],
+ ] );
+ $this->assertSame(
+ [
+ 'loggers' => [
+ '@default' => [
+ 'processors' => [ 'constructor' ],
+ 'handlers' => [ 'constructor' ],
+ ],
+ 'merged' => [
+ 'processors' => [ 'merged' ],
+ 'handlers' => [ 'merged' ],
+ ],
+ ],
+ 'processors' => [
+ 'constructor' => [
+ 'class' => 'constructor',
+ ],
+ 'merged' => [
+ 'class' => 'merged',
+ ],
+ ],
+ 'handlers' => [
+ 'constructor' => [
+ 'class' => 'constructor',
+ 'formatter' => 'constructor',
+ ],
+ 'merged' => [
+ 'class' => 'merged',
+ 'formatter' => 'merged',
+ ],
+ ],
+ 'formatters' => [
+ 'constructor' => [
+ 'class' => 'constructor',
+ ],
+ 'merged' => [
+ 'class' => 'merged',
+ ],
+ ],
+ 'magic' => [
+ 'idkfa' => [ 'xyzzy' ],
+ ],
+ ],
+ TestingAccessWrapper::newFromObject( $fixture )->config
+ );
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * 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
+ */
+
+namespace MediaWiki\Logger\Monolog;
+
+use PHPUnit_Framework_Error_Notice;
+
+/**
+ * @covers \MediaWiki\Logger\Monolog\AvroFormatter
+ */
+class AvroFormatterTest extends \MediaWikiUnitTestCase {
+
+ protected function setUp() {
+ if ( !class_exists( 'AvroStringIO' ) ) {
+ $this->markTestSkipped( 'Avro is required for the AvroFormatterTest' );
+ }
+ parent::setUp();
+ }
+
+ public function testSchemaNotAvailable() {
+ $formatter = new AvroFormatter( [] );
+ $this->setExpectedException(
+ 'PHPUnit_Framework_Error_Notice',
+ "The schema for channel 'marty' is not available"
+ );
+ $formatter->format( [ 'channel' => 'marty' ] );
+ }
+
+ public function testSchemaNotAvailableReturnValue() {
+ $formatter = new AvroFormatter( [] );
+ $noticeEnabled = PHPUnit_Framework_Error_Notice::$enabled;
+ // disable conversion of notices
+ PHPUnit_Framework_Error_Notice::$enabled = false;
+ // have to keep the user notice from being output
+ \Wikimedia\suppressWarnings();
+ $res = $formatter->format( [ 'channel' => 'marty' ] );
+ \Wikimedia\restoreWarnings();
+ PHPUnit_Framework_Error_Notice::$enabled = $noticeEnabled;
+ $this->assertNull( $res );
+ }
+
+ public function testDoesSomethingWhenSchemaAvailable() {
+ $formatter = new AvroFormatter( [
+ 'string' => [
+ 'schema' => [ 'type' => 'string' ],
+ 'revision' => 1010101,
+ ]
+ ] );
+ $res = $formatter->format( [
+ 'channel' => 'string',
+ 'context' => 'better to be',
+ ] );
+ $this->assertNotNull( $res );
+ // basically just tell us if avro changes its string encoding, or if
+ // we completely fail to generate a log message.
+ $this->assertEquals( 'AAAAAAAAD2m1GGJldHRlciB0byBiZQ==', base64_encode( $res ) );
+ }
+}
--- /dev/null
+<?php
+/**
+ * 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
+ */
+
+namespace MediaWiki\Logger\Monolog;
+
+use Monolog\Logger;
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * @covers \MediaWiki\Logger\Monolog\KafkaHandler
+ */
+class KafkaHandlerTest extends \MediaWikiUnitTestCase {
+
+ protected function setUp() {
+ if ( !class_exists( 'Monolog\Handler\AbstractProcessingHandler' )
+ || !class_exists( 'Kafka\Produce' )
+ ) {
+ $this->markTestSkipped( 'Monolog and Kafka are required for the KafkaHandlerTest' );
+ }
+
+ parent::setUp();
+ }
+
+ public function topicNamingProvider() {
+ return [
+ [ [], 'monolog_foo' ],
+ [ [ 'alias' => [ 'foo' => 'bar' ] ], 'bar' ]
+ ];
+ }
+
+ /**
+ * @dataProvider topicNamingProvider
+ */
+ public function testTopicNaming( $options, $expect ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( [ 'A' ] ) );
+ $produce->expects( $this->once() )
+ ->method( 'setMessages' )
+ ->with( $expect, $this->anything(), $this->anything() );
+ $produce->expects( $this->any() )
+ ->method( 'send' )
+ ->will( $this->returnValue( true ) );
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( [
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => [],
+ 'context' => [],
+ ] );
+ }
+
+ public function swallowsExceptionsWhenRequested() {
+ return [
+ // defaults to false
+ [ [], true ],
+ // also try false explicitly
+ [ [ 'swallowExceptions' => false ], true ],
+ // turn it on
+ [ [ 'swallowExceptions' => true ], false ],
+ ];
+ }
+
+ /**
+ * @dataProvider swallowsExceptionsWhenRequested
+ */
+ public function testGetAvailablePartitionsException( $options, $expectException ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->throwException( new \Kafka\Exception ) );
+ $produce->expects( $this->any() )
+ ->method( 'send' )
+ ->will( $this->returnValue( true ) );
+
+ if ( $expectException ) {
+ $this->setExpectedException( 'Kafka\Exception' );
+ }
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( [
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => [],
+ 'context' => [],
+ ] );
+
+ if ( !$expectException ) {
+ $this->assertTrue( true, 'no exception was thrown' );
+ }
+ }
+
+ /**
+ * @dataProvider swallowsExceptionsWhenRequested
+ */
+ public function testSendException( $options, $expectException ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( [ 'A' ] ) );
+ $produce->expects( $this->any() )
+ ->method( 'send' )
+ ->will( $this->throwException( new \Kafka\Exception ) );
+
+ if ( $expectException ) {
+ $this->setExpectedException( 'Kafka\Exception' );
+ }
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( [
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => [],
+ 'context' => [],
+ ] );
+
+ if ( !$expectException ) {
+ $this->assertTrue( true, 'no exception was thrown' );
+ }
+ }
+
+ public function testHandlesNullFormatterResult() {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( [ 'A' ] ) );
+ $mockMethod = $produce->expects( $this->exactly( 2 ) )
+ ->method( 'setMessages' );
+ $produce->expects( $this->any() )
+ ->method( 'send' )
+ ->will( $this->returnValue( true ) );
+ // evil hax
+ $matcher = TestingAccessWrapper::newFromObject( $mockMethod )->matcher;
+ TestingAccessWrapper::newFromObject( $matcher )->parametersMatcher =
+ new \PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters( [
+ [ $this->anything(), $this->anything(), [ 'words' ] ],
+ [ $this->anything(), $this->anything(), [ 'lines' ] ]
+ ] );
+
+ $formatter = $this->createMock( \Monolog\Formatter\FormatterInterface::class );
+ $formatter->expects( $this->any() )
+ ->method( 'format' )
+ ->will( $this->onConsecutiveCalls( 'words', null, 'lines' ) );
+
+ $handler = new KafkaHandler( $produce, [] );
+ $handler->setFormatter( $formatter );
+ for ( $i = 0; $i < 3; ++$i ) {
+ $handler->handle( [
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => [],
+ 'context' => [],
+ ] );
+ }
+ }
+
+ public function testBatchHandlesNullFormatterResult() {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( [ 'A' ] ) );
+ $produce->expects( $this->once() )
+ ->method( 'setMessages' )
+ ->with( $this->anything(), $this->anything(), [ 'words', 'lines' ] );
+ $produce->expects( $this->any() )
+ ->method( 'send' )
+ ->will( $this->returnValue( true ) );
+
+ $formatter = $this->createMock( \Monolog\Formatter\FormatterInterface::class );
+ $formatter->expects( $this->any() )
+ ->method( 'format' )
+ ->will( $this->onConsecutiveCalls( 'words', null, 'lines' ) );
+
+ $handler = new KafkaHandler( $produce, [] );
+ $handler->setFormatter( $formatter );
+ $handler->handleBatch( [
+ [
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => [],
+ 'context' => [],
+ ],
+ [
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => [],
+ 'context' => [],
+ ],
+ [
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => [],
+ 'context' => [],
+ ],
+ ] );
+ }
+}
--- /dev/null
+<?php
+/**
+ * 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
+ */
+
+namespace MediaWiki\Logger\Monolog;
+
+use AssertionError;
+use InvalidArgumentException;
+use LengthException;
+use LogicException;
+use Wikimedia\TestingAccessWrapper;
+
+class LineFormatterTest extends \MediaWikiUnitTestCase {
+
+ protected function setUp() {
+ if ( !class_exists( 'Monolog\Formatter\LineFormatter' ) ) {
+ $this->markTestSkipped( 'This test requires monolog to be installed' );
+ }
+ parent::setUp();
+ }
+
+ /**
+ * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
+ */
+ public function testNormalizeExceptionNoTrace() {
+ $fixture = new LineFormatter();
+ $fixture->includeStacktraces( false );
+ $fixture = TestingAccessWrapper::newFromObject( $fixture );
+ $boom = new InvalidArgumentException( 'boom', 0,
+ new LengthException( 'too long', 0,
+ new LogicException( 'Spock wuz here' )
+ )
+ );
+ $out = $fixture->normalizeException( $boom );
+ $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
+ $this->assertNotContains( "\n #0", $out );
+ }
+
+ /**
+ * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
+ */
+ public function testNormalizeExceptionTrace() {
+ $fixture = new LineFormatter();
+ $fixture->includeStacktraces( true );
+ $fixture = TestingAccessWrapper::newFromObject( $fixture );
+ $boom = new InvalidArgumentException( 'boom', 0,
+ new LengthException( 'too long', 0,
+ new LogicException( 'Spock wuz here' )
+ )
+ );
+ $out = $fixture->normalizeException( $boom );
+ $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
+ $this->assertContains( "\n #0", $out );
+ }
+
+ /**
+ * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
+ */
+ public function testNormalizeExceptionErrorNoTrace() {
+ if ( !class_exists( AssertionError::class ) ) {
+ $this->markTestSkipped( 'AssertionError class does not exist' );
+ }
+
+ $fixture = new LineFormatter();
+ $fixture->includeStacktraces( false );
+ $fixture = TestingAccessWrapper::newFromObject( $fixture );
+ $boom = new InvalidArgumentException( 'boom', 0,
+ new LengthException( 'too long', 0,
+ new AssertionError( 'Spock wuz here' )
+ )
+ );
+ $out = $fixture->normalizeException( $boom );
+ $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+ $this->assertContains( "\nCaused by: [Error AssertionError]", $out );
+ $this->assertNotContains( "\n #0", $out );
+ }
+
+ /**
+ * @covers MediaWiki\Logger\Monolog\LineFormatter::normalizeException
+ */
+ public function testNormalizeExceptionErrorTrace() {
+ if ( !class_exists( AssertionError::class ) ) {
+ $this->markTestSkipped( 'AssertionError class does not exist' );
+ }
+
+ $fixture = new LineFormatter();
+ $fixture->includeStacktraces( true );
+ $fixture = TestingAccessWrapper::newFromObject( $fixture );
+ $boom = new InvalidArgumentException( 'boom', 0,
+ new LengthException( 'too long', 0,
+ new AssertionError( 'Spock wuz here' )
+ )
+ );
+ $out = $fixture->normalizeException( $boom );
+ $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+ $this->assertContains( "\nCaused by: [Error AssertionError]", $out );
+ $this->assertContains( "\n #0", $out );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @group Diff
+ */
+class ArrayDiffFormatterTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @param Diff $input
+ * @param array $expectedOutput
+ * @dataProvider provideTestFormat
+ * @covers ArrayDiffFormatter::format
+ */
+ public function testFormat( $input, $expectedOutput ) {
+ $instance = new ArrayDiffFormatter();
+ $output = $instance->format( $input );
+ $this->assertEquals( $expectedOutput, $output );
+ }
+
+ private function getMockDiff( $edits ) {
+ $diff = $this->getMockBuilder( Diff::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $diff->expects( $this->any() )
+ ->method( 'getEdits' )
+ ->will( $this->returnValue( $edits ) );
+ return $diff;
+ }
+
+ private function getMockDiffOp( $type = null, $orig = [], $closing = [] ) {
+ $diffOp = $this->getMockBuilder( DiffOp::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $diffOp->expects( $this->any() )
+ ->method( 'getType' )
+ ->will( $this->returnValue( $type ) );
+ $diffOp->expects( $this->any() )
+ ->method( 'getOrig' )
+ ->will( $this->returnValue( $orig ) );
+ if ( $type === 'change' ) {
+ $diffOp->expects( $this->any() )
+ ->method( 'getClosing' )
+ ->with( $this->isType( 'integer' ) )
+ ->will( $this->returnCallback( function () {
+ return 'mockLine';
+ } ) );
+ } else {
+ $diffOp->expects( $this->any() )
+ ->method( 'getClosing' )
+ ->will( $this->returnValue( $closing ) );
+ }
+ return $diffOp;
+ }
+
+ public function provideTestFormat() {
+ $emptyArrayTestCases = [
+ $this->getMockDiff( [] ),
+ $this->getMockDiff( [ $this->getMockDiffOp( 'add' ) ] ),
+ $this->getMockDiff( [ $this->getMockDiffOp( 'delete' ) ] ),
+ $this->getMockDiff( [ $this->getMockDiffOp( 'change' ) ] ),
+ $this->getMockDiff( [ $this->getMockDiffOp( 'copy' ) ] ),
+ $this->getMockDiff( [ $this->getMockDiffOp( 'FOOBARBAZ' ) ] ),
+ $this->getMockDiff( [ $this->getMockDiffOp( 'add', 'line' ) ] ),
+ $this->getMockDiff( [ $this->getMockDiffOp( 'delete', [], [ 'line' ] ) ] ),
+ $this->getMockDiff( [ $this->getMockDiffOp( 'copy', [], [ 'line' ] ) ] ),
+ ];
+
+ $otherTestCases = [];
+ $otherTestCases[] = [
+ $this->getMockDiff( [ $this->getMockDiffOp( 'add', [], [ 'a1' ] ) ] ),
+ [ [ 'action' => 'add', 'new' => 'a1', 'newline' => 1 ] ],
+ ];
+ $otherTestCases[] = [
+ $this->getMockDiff( [ $this->getMockDiffOp( 'add', [], [ 'a1', 'a2' ] ) ] ),
+ [
+ [ 'action' => 'add', 'new' => 'a1', 'newline' => 1 ],
+ [ 'action' => 'add', 'new' => 'a2', 'newline' => 2 ],
+ ],
+ ];
+ $otherTestCases[] = [
+ $this->getMockDiff( [ $this->getMockDiffOp( 'delete', [ 'd1' ] ) ] ),
+ [ [ 'action' => 'delete', 'old' => 'd1', 'oldline' => 1 ] ],
+ ];
+ $otherTestCases[] = [
+ $this->getMockDiff( [ $this->getMockDiffOp( 'delete', [ 'd1', 'd2' ] ) ] ),
+ [
+ [ 'action' => 'delete', 'old' => 'd1', 'oldline' => 1 ],
+ [ 'action' => 'delete', 'old' => 'd2', 'oldline' => 2 ],
+ ],
+ ];
+ $otherTestCases[] = [
+ $this->getMockDiff( [ $this->getMockDiffOp( 'change', [ 'd1' ], [ 'a1' ] ) ] ),
+ [ [
+ 'action' => 'change',
+ 'old' => 'd1',
+ 'new' => 'mockLine',
+ 'newline' => 1, 'oldline' => 1
+ ] ],
+ ];
+ $otherTestCases[] = [
+ $this->getMockDiff( [ $this->getMockDiffOp(
+ 'change',
+ [ 'd1', 'd2' ],
+ [ 'a1', 'a2' ]
+ ) ] ),
+ [
+ [
+ 'action' => 'change',
+ 'old' => 'd1',
+ 'new' => 'mockLine',
+ 'newline' => 1, 'oldline' => 1
+ ],
+ [
+ 'action' => 'change',
+ 'old' => 'd2',
+ 'new' => 'mockLine',
+ 'newline' => 2, 'oldline' => 2
+ ],
+ ],
+ ];
+
+ $testCases = [];
+ foreach ( $emptyArrayTestCases as $testCase ) {
+ $testCases[] = [ $testCase, [] ];
+ }
+ foreach ( $otherTestCases as $testCase ) {
+ $testCases[] = [ $testCase[0], $testCase[1] ];
+ }
+ return $testCases;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Addshore
+ *
+ * @group Diff
+ */
+class DiffOpTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers DiffOp::getType
+ */
+ public function testGetType() {
+ $obj = new FakeDiffOp();
+ $obj->type = 'foo';
+ $this->assertEquals( 'foo', $obj->getType() );
+ }
+
+ /**
+ * @covers DiffOp::getOrig
+ */
+ public function testGetOrig() {
+ $obj = new FakeDiffOp();
+ $obj->orig = [ 'foo' ];
+ $this->assertEquals( [ 'foo' ], $obj->getOrig() );
+ }
+
+ /**
+ * @covers DiffOp::getClosing
+ */
+ public function testGetClosing() {
+ $obj = new FakeDiffOp();
+ $obj->closing = [ 'foo' ];
+ $this->assertEquals( [ 'foo' ], $obj->getClosing() );
+ }
+
+ /**
+ * @covers DiffOp::getClosing
+ */
+ public function testGetClosingWithParameter() {
+ $obj = new FakeDiffOp();
+ $obj->closing = [ 'foo', 'bar', 'baz' ];
+ $this->assertEquals( 'foo', $obj->getClosing( 0 ) );
+ $this->assertEquals( 'bar', $obj->getClosing( 1 ) );
+ $this->assertEquals( 'baz', $obj->getClosing( 2 ) );
+ $this->assertEquals( null, $obj->getClosing( 3 ) );
+ }
+
+ /**
+ * @covers DiffOp::norig
+ */
+ public function testNorig() {
+ $obj = new FakeDiffOp();
+ $this->assertEquals( 0, $obj->norig() );
+ $obj->orig = [ 'foo' ];
+ $this->assertEquals( 1, $obj->norig() );
+ }
+
+ /**
+ * @covers DiffOp::nclosing
+ */
+ public function testNclosing() {
+ $obj = new FakeDiffOp();
+ $this->assertEquals( 0, $obj->nclosing() );
+ $obj->closing = [ 'foo' ];
+ $this->assertEquals( 1, $obj->nclosing() );
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @group Diff
+ */
+class DiffTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers Diff::getEdits
+ */
+ public function testGetEdits() {
+ $obj = new Diff( [], [] );
+ $obj->edits = 'FooBarBaz';
+ $this->assertEquals( 'FooBarBaz', $obj->getEdits() );
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Antoine Musso
+ * @copyright Copyright © 2013, Antoine Musso
+ * @copyright Copyright © 2013, Wikimedia Foundation Inc.
+ * @file
+ */
+
+class MWExceptionHandlerTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers MWExceptionHandler::getRedactedTrace
+ */
+ public function testGetRedactedTrace() {
+ $refvar = 'value';
+ try {
+ $array = [ 'a', 'b' ];
+ $object = new stdClass();
+ self::helperThrowAnException( $array, $object, $refvar );
+ } catch ( Exception $e ) {
+ }
+
+ # Make sure our stack trace contains an array and an object passed to
+ # some function in the stacktrace. Else, we can not assert the trace
+ # redaction achieved its job.
+ $trace = $e->getTrace();
+ $hasObject = false;
+ $hasArray = false;
+ foreach ( $trace as $frame ) {
+ if ( !isset( $frame['args'] ) ) {
+ continue;
+ }
+ foreach ( $frame['args'] as $arg ) {
+ $hasObject = $hasObject || is_object( $arg );
+ $hasArray = $hasArray || is_array( $arg );
+ }
+
+ if ( $hasObject && $hasArray ) {
+ break;
+ }
+ }
+ $this->assertTrue( $hasObject,
+ "The stacktrace must have a function having an object has parameter" );
+ $this->assertTrue( $hasArray,
+ "The stacktrace must have a function having an array has parameter" );
+
+ # Now we redact the trace.. and make sure no function arguments are
+ # arrays or objects.
+ $redacted = MWExceptionHandler::getRedactedTrace( $e );
+
+ foreach ( $redacted as $frame ) {
+ if ( !isset( $frame['args'] ) ) {
+ continue;
+ }
+ foreach ( $frame['args'] as $arg ) {
+ $this->assertNotInternalType( 'array', $arg );
+ $this->assertNotInternalType( 'object', $arg );
+ }
+ }
+
+ $this->assertEquals( 'value', $refvar, 'Ensuring reference variable wasn\'t changed' );
+ }
+
+ /**
+ * Helper function for testExpandArgumentsInCall
+ *
+ * Pass it an object and an array, and something by reference :-)
+ *
+ * @throws Exception
+ */
+ protected static function helperThrowAnException( $a, $b, &$c ) {
+ throw new Exception();
+ }
+}
--- /dev/null
+<?php
+
+class InstallDocFormatterTest extends \MediaWikiUnitTestCase {
+ /**
+ * @covers InstallDocFormatter
+ * @dataProvider provideDocFormattingTests
+ */
+ public function testFormat( $expected, $unformattedText, $message = '' ) {
+ $this->assertEquals(
+ $expected,
+ InstallDocFormatter::format( $unformattedText ),
+ $message
+ );
+ }
+
+ /**
+ * Provider for testFormat()
+ */
+ public static function provideDocFormattingTests() {
+ # Format: (expected string, unformattedText string, optional message)
+ return [
+ # Escape some wikitext
+ [ 'Install <tag>', 'Install <tag>', 'Escaping <' ],
+ [ 'Install {{template}}', 'Install {{template}}', 'Escaping [[' ],
+ [ 'Install [[page]]', 'Install [[page]]', 'Escaping {{' ],
+ [ 'Install __TOC__', 'Install __TOC__', 'Escaping __' ],
+ [ 'Install ', "Install \r", 'Removing \r' ],
+
+ # Transform \t{1,2} into :{1,2}
+ [ ':One indentation', "\tOne indentation", 'Replacing a single \t' ],
+ [ '::Two indentations', "\t\tTwo indentations", 'Replacing 2 x \t' ],
+
+ # Transform 'T123' links
+ [
+ '<span class="config-plainlink">[https://phabricator.wikimedia.org/T123 T123]</span>',
+ 'T123', 'Testing T123 links' ],
+ [
+ 'bug <span class="config-plainlink">[https://phabricator.wikimedia.org/T123 T123]</span>',
+ 'bug T123', 'Testing bug T123 links' ],
+ [
+ '(<span class="config-plainlink">[https://phabricator.wikimedia.org/T987654 T987654]</span>)',
+ '(T987654)', 'Testing (T987654) links' ],
+
+ # "Tabc" shouldn't work
+ [ 'Tfoobar', 'Tfoobar', "Don't match T followed by non-digits" ],
+ [ 'T!!fakefake!!', 'T!!fakefake!!', "Don't match T followed by non-digits" ],
+
+ # Transform 'bug 123' links
+ [
+ '<span class="config-plainlink">[https://bugzilla.wikimedia.org/123 bug 123]</span>',
+ 'bug 123', 'Testing bug 123 links' ],
+ [
+ '(<span class="config-plainlink">[https://bugzilla.wikimedia.org/987654 bug 987654]</span>)',
+ '(bug 987654)', 'Testing (bug 987654) links' ],
+
+ # "bug abc" shouldn't work
+ [ 'bug foobar', 'bug foobar', "Don't match bug followed by non-digits" ],
+ [ 'bug !!fakefake!!', 'bug !!fakefake!!', "Don't match bug followed by non-digits" ],
+
+ # Transform '$wgFooBar' links
+ [
+ '<span class="config-plainlink">'
+ . '[https://www.mediawiki.org/wiki/Manual:$wgFooBar $wgFooBar]</span>',
+ '$wgFooBar', 'Testing basic $wgFooBar' ],
+ [
+ '<span class="config-plainlink">'
+ . '[https://www.mediawiki.org/wiki/Manual:$wgFooBar45 $wgFooBar45]</span>',
+ '$wgFooBar45', 'Testing $wgFooBar45 (with numbers)' ],
+ [
+ '<span class="config-plainlink">'
+ . '[https://www.mediawiki.org/wiki/Manual:$wgFoo_Bar $wgFoo_Bar]</span>',
+ '$wgFoo_Bar', 'Testing $wgFoo_Bar (with underscore)' ],
+
+ # Icky variables that shouldn't link
+ [
+ '$myAwesomeVariable',
+ '$myAwesomeVariable',
+ 'Testing $myAwesomeVariable (not starting with $wg)'
+ ],
+ [ '$()not!a&Var', '$()not!a&Var', 'Testing $()not!a&Var (obviously not a variable)' ],
+ ];
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group Installer
+ */
+class OracleInstallerTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @dataProvider provideOracleConnectStrings
+ * @covers OracleInstaller::checkConnectStringFormat
+ */
+ public function testCheckConnectStringFormat( $expected, $connectString, $msg = '' ) {
+ $validity = $expected ? 'should be valid' : 'should NOT be valid';
+ $msg = "'$connectString' ($msg) $validity.";
+ $this->assertEquals( $expected,
+ OracleInstaller::checkConnectStringFormat( $connectString ),
+ $msg
+ );
+ }
+
+ /**
+ * Provider to test OracleInstaller::checkConnectStringFormat()
+ */
+ function provideOracleConnectStrings() {
+ // expected result, connectString[, message]
+ return [
+ [ true, 'simple_01', 'Simple TNS name' ],
+ [ true, 'simple_01.world', 'TNS name with domain' ],
+ [ true, 'simple_01.domain.net', 'TNS name with domain' ],
+ [ true, 'host123', 'Host only' ],
+ [ true, 'host123.domain.net', 'FQDN only' ],
+ [ true, '//host123.domain.net', 'FQDN URL only' ],
+ [ true, '123.223.213.132', 'Host IP only' ],
+ [ true, 'host:1521', 'Host and port' ],
+ [ true, 'host:1521/service', 'Host, port and service' ],
+ [ true, 'host:1521/service:shared', 'Host, port, service and shared server type' ],
+ [ true, 'host:1521/service:dedicated', 'Host, port, service and dedicated server type' ],
+ [ true, 'host:1521/service:pooled', 'Host, port, service and pooled server type' ],
+ [
+ true,
+ 'host:1521/service:shared/instance1',
+ 'Host, port, service, server type and instance'
+ ],
+ [ true, 'host:1521//instance1', 'Host, port and instance' ],
+ ];
+ }
+
+}
--- /dev/null
+<?php
+
+use MediaWiki\Interwiki\InterwikiLookupAdapter;
+
+/**
+ * @covers MediaWiki\Interwiki\InterwikiLookupAdapter
+ *
+ * @group MediaWiki
+ * @group Interwiki
+ */
+class InterwikiLookupAdapterTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @var InterwikiLookupAdapter
+ */
+ private $interwikiLookup;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->interwikiLookup = new InterwikiLookupAdapter(
+ $this->getSiteLookup( $this->getSites() )
+ );
+ }
+
+ public function testIsValidInterwiki() {
+ $this->assertTrue(
+ $this->interwikiLookup->isValidInterwiki( 'enwt' ),
+ 'enwt known prefix is valid'
+ );
+ $this->assertTrue(
+ $this->interwikiLookup->isValidInterwiki( 'foo' ),
+ 'foo site known prefix is valid'
+ );
+ $this->assertFalse(
+ $this->interwikiLookup->isValidInterwiki( 'xyz' ),
+ 'unknown prefix is not valid'
+ );
+ }
+
+ public function testFetch() {
+ $interwiki = $this->interwikiLookup->fetch( '' );
+ $this->assertNull( $interwiki );
+
+ $interwiki = $this->interwikiLookup->fetch( 'xyz' );
+ $this->assertFalse( $interwiki );
+
+ $interwiki = $this->interwikiLookup->fetch( 'foo' );
+ $this->assertInstanceOf( Interwiki::class, $interwiki );
+ $this->assertSame( 'foobar', $interwiki->getWikiID() );
+
+ $interwiki = $this->interwikiLookup->fetch( 'enwt' );
+ $this->assertInstanceOf( Interwiki::class, $interwiki );
+
+ $this->assertSame( 'https://en.wiktionary.org/wiki/$1', $interwiki->getURL(), 'getURL' );
+ $this->assertSame( 'https://en.wiktionary.org/w/api.php', $interwiki->getAPI(), 'getAPI' );
+ $this->assertSame( 'enwiktionary', $interwiki->getWikiID(), 'getWikiID' );
+ $this->assertTrue( $interwiki->isLocal(), 'isLocal' );
+ }
+
+ public function testGetAllPrefixes() {
+ $foo = [
+ 'iw_prefix' => 'foo',
+ 'iw_url' => '',
+ 'iw_api' => '',
+ 'iw_wikiid' => 'foobar',
+ 'iw_local' => false,
+ 'iw_trans' => false,
+ ];
+ $enwt = [
+ 'iw_prefix' => 'enwt',
+ 'iw_url' => 'https://en.wiktionary.org/wiki/$1',
+ 'iw_api' => 'https://en.wiktionary.org/w/api.php',
+ 'iw_wikiid' => 'enwiktionary',
+ 'iw_local' => true,
+ 'iw_trans' => false,
+ ];
+
+ $this->assertEquals(
+ [ $foo, $enwt ],
+ $this->interwikiLookup->getAllPrefixes(),
+ 'getAllPrefixes()'
+ );
+
+ $this->assertEquals(
+ [ $foo ],
+ $this->interwikiLookup->getAllPrefixes( false ),
+ 'get external prefixes'
+ );
+
+ $this->assertEquals(
+ [ $enwt ],
+ $this->interwikiLookup->getAllPrefixes( true ),
+ 'get local prefixes'
+ );
+ }
+
+ private function getSiteLookup( SiteList $sites ) {
+ $siteLookup = $this->getMockBuilder( SiteLookup::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $siteLookup->expects( $this->any() )
+ ->method( 'getSites' )
+ ->will( $this->returnValue( $sites ) );
+
+ return $siteLookup;
+ }
+
+ private function getSites() {
+ $sites = [];
+
+ $site = new Site();
+ $site->setGlobalId( 'foobar' );
+ $site->addInterwikiId( 'foo' );
+ $site->setSource( 'external' );
+ $sites[] = $site;
+
+ $site = new MediaWikiSite();
+ $site->setGlobalId( 'enwiktionary' );
+ $site->setGroup( 'wiktionary' );
+ $site->setLanguageCode( 'en' );
+ $site->addNavigationId( 'enwiktionary' );
+ $site->addInterwikiId( 'enwt' );
+ $site->setSource( 'local' );
+ $site->setPath( MediaWikiSite::PATH_PAGE, "https://en.wiktionary.org/wiki/$1" );
+ $site->setPath( MediaWikiSite::PATH_FILE, "https://en.wiktionary.org/w/$1" );
+ $sites[] = $site;
+
+ return new SiteList( $sites );
+ }
+
+}
--- /dev/null
+<?php
+
+class ReplicatedBagOStuffTest extends \MediaWikiUnitTestCase {
+ /** @var HashBagOStuff */
+ private $writeCache;
+ /** @var HashBagOStuff */
+ private $readCache;
+ /** @var ReplicatedBagOStuff */
+ private $cache;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->writeCache = new HashBagOStuff();
+ $this->readCache = new HashBagOStuff();
+ $this->cache = new ReplicatedBagOStuff( [
+ 'writeFactory' => $this->writeCache,
+ 'readFactory' => $this->readCache,
+ ] );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::set
+ */
+ public function testSet() {
+ $key = 'a key';
+ $value = 'a value';
+ $this->cache->set( $key, $value );
+
+ // Write to master.
+ $this->assertEquals( $value, $this->writeCache->get( $key ) );
+ // Don't write to replica. Replication is deferred to backend.
+ $this->assertFalse( $this->readCache->get( $key ) );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::get
+ */
+ public function testGet() {
+ $key = 'a key';
+
+ $write = 'one value';
+ $this->writeCache->set( $key, $write );
+ $read = 'another value';
+ $this->readCache->set( $key, $read );
+
+ // Read from replica.
+ $this->assertEquals( $read, $this->cache->get( $key ) );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::get
+ */
+ public function testGetAbsent() {
+ $key = 'a key';
+ $value = 'a value';
+ $this->writeCache->set( $key, $value );
+
+ // Don't read from master. No failover if value is absent.
+ $this->assertFalse( $this->cache->get( $key ) );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group Media
+ */
+class IPTCTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers IPTC::getCharset
+ */
+ public function testRecognizeUtf8() {
+ // utf-8 is the only one used in practise.
+ $res = IPTC::getCharset( "\x1b%G" );
+ $this->assertEquals( 'UTF-8', $res );
+ }
+
+ /**
+ * @covers IPTC::parse
+ */
+ public function testIPTCParseNoCharset88591() {
+ // basically IPTC for keyword with value of 0xBC which is 1/4 in iso-8859-1
+ // This data doesn't specify a charset. We're supposed to guess
+ // (which basically means utf-8 if valid, windows 1252 (iso 8859-1) if not)
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x06\x1c\x02\x19\x00\x01\xBC";
+ $res = IPTC::parse( $iptcData );
+ $this->assertEquals( [ '¼' ], $res['Keywords'] );
+ }
+
+ /**
+ * @covers IPTC::parse
+ */
+ public function testIPTCParseNoCharset88591b() {
+ /* This one contains a sequence that's valid iso 8859-1 but not valid utf8 */
+ /* \xC3 = Ã, \xB8 = ¸ */
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x09\x1c\x02\x19\x00\x04\xC3\xC3\xC3\xB8";
+ $res = IPTC::parse( $iptcData );
+ $this->assertEquals( [ 'ÃÃø' ], $res['Keywords'] );
+ }
+
+ /**
+ * Same as testIPTCParseNoCharset88591b, but forcing the charset to utf-8.
+ * What should happen is the first "\xC3\xC3" should be dropped as invalid,
+ * leaving \xC3\xB8, which is ø
+ * @covers IPTC::parse
+ */
+ public function testIPTCParseForcedUTFButInvalid() {
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x11\x1c\x02\x19\x00\x04\xC3\xC3\xC3\xB8"
+ . "\x1c\x01\x5A\x00\x03\x1B\x25\x47";
+ $res = IPTC::parse( $iptcData );
+ $this->assertEquals( [ 'ø' ], $res['Keywords'] );
+ }
+
+ /**
+ * @covers IPTC::parse
+ */
+ public function testIPTCParseNoCharsetUTF8() {
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x07\x1c\x02\x19\x00\x02¼";
+ $res = IPTC::parse( $iptcData );
+ $this->assertEquals( [ '¼' ], $res['Keywords'] );
+ }
+
+ /**
+ * Testing something that has 2 values for keyword
+ * @covers IPTC::parse
+ */
+ public function testIPTCParseMulti() {
+ $iptcData = /* identifier */ "Photoshop 3.0\08BIM\4\4"
+ /* length */ . "\0\0\0\0\0\x0D"
+ . "\x1c\x02\x19" . "\x00\x01" . "\xBC"
+ . "\x1c\x02\x19" . "\x00\x02" . "\xBC\xBD";
+ $res = IPTC::parse( $iptcData );
+ $this->assertEquals( [ '¼', '¼½' ], $res['Keywords'] );
+ }
+
+ /**
+ * @covers IPTC::parse
+ */
+ public function testIPTCParseUTF8() {
+ // This has the magic "\x1c\x01\x5A\x00\x03\x1B\x25\x47" which marks content as UTF8.
+ $iptcData =
+ "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x0F\x1c\x02\x19\x00\x02¼\x1c\x01\x5A\x00\x03\x1B\x25\x47";
+ $res = IPTC::parse( $iptcData );
+ $this->assertEquals( [ '¼' ], $res['Keywords'] );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group Media
+ */
+class MediaHandlerTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers MediaHandler::fitBoxWidth
+ *
+ * @dataProvider provideTestFitBoxWidth
+ */
+ public function testFitBoxWidth( $width, $height, $max, $expected ) {
+ $y = round( $expected * $height / $width );
+ $result = MediaHandler::fitBoxWidth( $width, $height, $max );
+ $y2 = round( $result * $height / $width );
+ $this->assertEquals( $expected,
+ $result,
+ "($width, $height, $max) wanted: {$expected}x$y, got: {z$result}x$y2" );
+ }
+
+ public static function provideTestFitBoxWidth() {
+ return array_merge(
+ static::generateTestFitBoxWidthData( 50, 50, [
+ 50 => 50,
+ 17 => 17,
+ 18 => 18 ]
+ ),
+ static::generateTestFitBoxWidthData( 366, 300, [
+ 50 => 61,
+ 17 => 21,
+ 18 => 22 ]
+ ),
+ static::generateTestFitBoxWidthData( 300, 366, [
+ 50 => 41,
+ 17 => 14,
+ 18 => 15 ]
+ ),
+ static::generateTestFitBoxWidthData( 100, 400, [
+ 50 => 12,
+ 17 => 4,
+ 18 => 4 ]
+ )
+ );
+ }
+
+ /**
+ * Generate single test cases by combining the dimensions and tests contents
+ *
+ * It creates:
+ * [$width, $height, $max, $expected],
+ * [$width, $height, $max2, $expected2], ...
+ * out of parameters:
+ * $width, $height, { $max => $expected, $max2 => $expected2, ... }
+ *
+ * @param int $width
+ * @param int $height
+ * @param array $tests associative array of $max => $expected values
+ * @return array
+ */
+ private static function generateTestFitBoxWidthData( $width, $height, $tests ) {
+ $result = [];
+ foreach ( $tests as $max => $expected ) {
+ $result[] = [ $width, $height, $max, $expected ];
+ }
+ return $result;
+ }
+}
--- /dev/null
+<?php
+/**
+ * @group BagOStuff
+ */
+class MemcachedBagOStuffTest extends \MediaWikiUnitTestCase {
+ /** @var MemcachedBagOStuff */
+ private $cache;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->cache = new MemcachedPhpBagOStuff( [ 'keyspace' => 'test', 'servers' => [] ] );
+ }
+
+ /**
+ * @covers MemcachedBagOStuff::makeKey
+ */
+ public function testKeyNormalization() {
+ $this->assertEquals(
+ 'test:vanilla',
+ $this->cache->makeKey( 'vanilla' )
+ );
+
+ $this->assertEquals(
+ 'test:punctuation_marks_are_ok:!@$^&*()',
+ $this->cache->makeKey( 'punctuation_marks_are_ok', '!@$^&*()' )
+ );
+
+ $this->assertEquals(
+ 'test:but_spaces:hashes%23:and%0Anewlines:are_not',
+ $this->cache->makeKey( 'but spaces', 'hashes#', "and\nnewlines", 'are_not' )
+ );
+
+ $this->assertEquals(
+ 'test:this:key:contains:%F0%9D%95%9E%F0%9D%95%A6%F0%9D%95%9D%F0%9D%95%A5%F0%9' .
+ 'D%95%9A%F0%9D%95%93%F0%9D%95%AA%F0%9D%95%A5%F0%9D%95%96:characters',
+ $this->cache->makeKey( 'this', 'key', 'contains', '𝕞𝕦𝕝𝕥𝕚𝕓𝕪𝕥𝕖', 'characters' )
+ );
+
+ $this->assertEquals(
+ 'test:this:key:contains:#c118f92685a635cb843039de50014c9c',
+ $this->cache->makeKey( 'this', 'key', 'contains', '𝕥𝕠𝕠 𝕞𝕒𝕟𝕪 𝕞𝕦𝕝𝕥𝕚𝕓𝕪𝕥𝕖 𝕔𝕙𝕒𝕣𝕒𝕔𝕥𝕖𝕣𝕤' )
+ );
+
+ $this->assertEquals(
+ 'test:BagOStuff-long-key:##dc89dcb43b28614da27660240af478b5',
+ $this->cache->makeKey( '𝕖𝕧𝕖𝕟', '𝕚𝕗', '𝕨𝕖', '𝕄𝔻𝟝', '𝕖𝕒𝕔𝕙',
+ '𝕒𝕣𝕘𝕦𝕞𝕖𝕟𝕥', '𝕥𝕙𝕚𝕤', '𝕜𝕖𝕪', '𝕨𝕠𝕦𝕝𝕕', '𝕤𝕥𝕚𝕝𝕝', '𝕓𝕖', '𝕥𝕠𝕠', '𝕝𝕠𝕟𝕘' )
+ );
+
+ $this->assertEquals(
+ 'test:%23%235820ad1d105aa4dc698585c39df73e19',
+ $this->cache->makeKey( '##5820ad1d105aa4dc698585c39df73e19' )
+ );
+
+ $this->assertEquals(
+ 'test:percent_is_escaped:!@$%25^&*()',
+ $this->cache->makeKey( 'percent_is_escaped', '!@$%^&*()' )
+ );
+
+ $this->assertEquals(
+ 'test:colon_is_escaped:!@$%3A^&*()',
+ $this->cache->makeKey( 'colon_is_escaped', '!@$:^&*()' )
+ );
+
+ $this->assertEquals(
+ 'test:long_key_part_hashed:#0244f7b1811d982dd932dd7de01465ac',
+ $this->cache->makeKey( 'long_key_part_hashed', str_repeat( 'y', 500 ) )
+ );
+ }
+
+ /**
+ * @dataProvider validKeyProvider
+ * @covers MemcachedBagOStuff::validateKeyEncoding
+ */
+ public function testValidateKeyEncoding( $key ) {
+ $this->assertSame( $key, $this->cache->validateKeyEncoding( $key ) );
+ }
+
+ public function validKeyProvider() {
+ return [
+ 'empty' => [ '' ],
+ 'digits' => [ '09' ],
+ 'letters' => [ 'AZaz' ],
+ 'ASCII special characters' => [ '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' ],
+ ];
+ }
+
+ /**
+ * @dataProvider invalidKeyProvider
+ * @covers MemcachedBagOStuff::validateKeyEncoding
+ */
+ public function testValidateKeyEncodingThrowsException( $key ) {
+ $this->setExpectedException( Exception::class );
+ $this->cache->validateKeyEncoding( $key );
+ }
+
+ public function invalidKeyProvider() {
+ return [
+ [ "\x00" ],
+ [ ' ' ],
+ [ "\x1F" ],
+ [ "\x7F" ],
+ [ "\x80" ],
+ [ "\xFF" ],
+ ];
+ }
+}
--- /dev/null
+<?php
+/**
+ * @group BagOStuff
+ *
+ * @covers RESTBagOStuff
+ */
+class RESTBagOStuffTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @var MultiHttpClient
+ */
+ private $client;
+ /**
+ * @var RESTBagOStuff
+ */
+ private $bag;
+
+ public function setUp() {
+ parent::setUp();
+ $this->client =
+ $this->getMockBuilder( MultiHttpClient::class )
+ ->setConstructorArgs( [ [] ] )
+ ->setMethods( [ 'run' ] )
+ ->getMock();
+ $this->bag = new RESTBagOStuff( [ 'client' => $this->client, 'url' => 'http://test/rest/' ] );
+ }
+
+ public function testGet() {
+ $this->client->expects( $this->once() )->method( 'run' )->with( [
+ 'method' => 'GET',
+ 'url' => 'http://test/rest/42xyz42',
+ 'headers' => []
+ // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
+ ] )->willReturn( [ 200, 'OK', [], '"somedata"', 0 ] );
+ $result = $this->bag->get( '42xyz42' );
+ $this->assertEquals( 'somedata', $result );
+ }
+
+ public function testGetNotExist() {
+ $this->client->expects( $this->once() )->method( 'run' )->with( [
+ 'method' => 'GET',
+ 'url' => 'http://test/rest/42xyz42',
+ 'headers' => []
+ // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
+ ] )->willReturn( [ 404, 'Not found', [], 'Nothing to see here', 0 ] );
+ $result = $this->bag->get( '42xyz42' );
+ $this->assertFalse( $result );
+ }
+
+ public function testGetBadClient() {
+ $this->client->expects( $this->once() )->method( 'run' )->with( [
+ 'method' => 'GET',
+ 'url' => 'http://test/rest/42xyz42',
+ 'headers' => []
+ // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
+ ] )->willReturn( [ 0, '', [], '', 'cURL has failed you today' ] );
+ $result = $this->bag->get( '42xyz42' );
+ $this->assertFalse( $result );
+ $this->assertEquals( BagOStuff::ERR_UNREACHABLE, $this->bag->getLastError() );
+ }
+
+ public function testGetBadServer() {
+ $this->client->expects( $this->once() )->method( 'run' )->with( [
+ 'method' => 'GET',
+ 'url' => 'http://test/rest/42xyz42',
+ 'headers' => []
+ // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
+ ] )->willReturn( [ 500, 'Too busy', [], 'Server is too busy', '' ] );
+ $result = $this->bag->get( '42xyz42' );
+ $this->assertFalse( $result );
+ $this->assertEquals( BagOStuff::ERR_UNEXPECTED, $this->bag->getLastError() );
+ }
+
+ public function testPut() {
+ $this->client->expects( $this->once() )->method( 'run' )->with( [
+ 'method' => 'PUT',
+ 'url' => 'http://test/rest/42xyz42',
+ 'body' => '"postdata"',
+ 'headers' => []
+ // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
+ ] )->willReturn( [ 200, 'OK', [], 'Done', 0 ] );
+ $result = $this->bag->set( '42xyz42', 'postdata' );
+ $this->assertTrue( $result );
+ }
+
+ public function testDelete() {
+ $this->client->expects( $this->once() )->method( 'run' )->with( [
+ 'method' => 'DELETE',
+ 'url' => 'http://test/rest/42xyz42',
+ 'headers' => []
+ // list( $rcode, $rdesc, $rhdrs, $rbody, $rerr )
+ ] )->willReturn( [ 200, 'OK', [], 'Done', 0 ] );
+ $result = $this->bag->delete( '42xyz42' );
+ $this->assertTrue( $result );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group Parser
+ * @covers MWTidy
+ */
+class TidyTest extends \MediaWikiUnitTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+ if ( !MWTidy::isEnabled() ) {
+ $this->markTestSkipped( 'Tidy not found' );
+ }
+ }
+
+ /**
+ * @dataProvider provideTestWrapping
+ */
+ public function testTidyWrapping( $expected, $text, $msg = '' ) {
+ $text = MWTidy::tidy( $text );
+ // We don't care about where Tidy wants to stick is <p>s
+ $text = trim( preg_replace( '#</?p>#', '', $text ) );
+ // Windows, we love you!
+ $text = str_replace( "\r", '', $text );
+ $this->assertEquals( $expected, $text, $msg );
+ }
+
+ public static function provideTestWrapping() {
+ $testMathML = <<<'MathML'
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <mi>a</mi>
+ <mo>⁢</mo>
+ <msup>
+ <mi>x</mi>
+ <mn>2</mn>
+ </msup>
+ <mo>+</mo>
+ <mi>b</mi>
+ <mo>⁢ </mo>
+ <mi>x</mi>
+ <mo>+</mo>
+ <mi>c</mi>
+ </mrow>
+ </math>
+MathML;
+ return [
+ [
+ '<mw:editsection page="foo" section="bar">foo</mw:editsection>',
+ '<mw:editsection page="foo" section="bar">foo</mw:editsection>',
+ '<mw:editsection> should survive tidy'
+ ],
+ [
+ '<editsection page="foo" section="bar">foo</editsection>',
+ '<editsection page="foo" section="bar">foo</editsection>',
+ '<editsection> should survive tidy'
+ ],
+ [ '<mw:toc>foo</mw:toc>', '<mw:toc>foo</mw:toc>', '<mw:toc> should survive tidy' ],
+ [ "<link foo=\"bar\" />foo", '<link foo="bar"/>foo', '<link> should survive tidy' ],
+ [ "<meta foo=\"bar\" />foo", '<meta foo="bar"/>foo', '<meta> should survive tidy' ],
+ [ $testMathML, $testMathML, '<math> should survive tidy' ],
+ ];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Testing framework for the Password infrastructure
+ *
+ * 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
+ */
+
+/**
+ * @covers InvalidPassword
+ */
+class PasswordTest extends \MediaWikiUnitTestCase {
+ public function testInvalidPlaintext() {
+ $passwordFactory = new PasswordFactory();
+ $invalid = $passwordFactory->newFromPlaintext( null );
+
+ $this->assertInstanceOf( InvalidPassword::class, $invalid );
+ }
+}
--- /dev/null
+<?php
+/**
+ * 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
+ */
+
+use MediaWiki\Preferences\IntvalFilter;
+use MediaWiki\Preferences\MultiUsernameFilter;
+use MediaWiki\Preferences\TimezoneFilter;
+
+/**
+ * @group Preferences
+ */
+class FiltersTest extends \MediaWikiUnitTestCase {
+ /**
+ * @covers MediaWiki\Preferences\IntvalFilter::filterFromForm()
+ * @covers MediaWiki\Preferences\IntvalFilter::filterForForm()
+ */
+ public function testIntvalFilter() {
+ $filter = new IntvalFilter();
+ self::assertSame( 0, $filter->filterFromForm( '0' ) );
+ self::assertSame( 3, $filter->filterFromForm( '3' ) );
+ self::assertSame( '123', $filter->filterForForm( '123' ) );
+ }
+
+ /**
+ * @covers MediaWiki\Preferences\TimezoneFilter::filterFromForm()
+ * @dataProvider provideTimezoneFilter
+ *
+ * @param string $input
+ * @param string $expected
+ */
+ public function testTimezoneFilter( $input, $expected ) {
+ $filter = new TimezoneFilter();
+ $result = $filter->filterFromForm( $input );
+ self::assertEquals( $expected, $result );
+ }
+
+ public function provideTimezoneFilter() {
+ return [
+ [ 'ZoneInfo', 'Offset|0' ],
+ [ 'ZoneInfo|bogus', 'Offset|0' ],
+ [ 'System', 'System' ],
+ [ '2:30', 'Offset|150' ],
+ ];
+ }
+
+ /**
+ * @covers MediaWiki\Preferences\MultiUsernameFilter::filterFromForm()
+ * @dataProvider provideMultiUsernameFilterFrom
+ *
+ * @param string $input
+ * @param string|null $expected
+ */
+ public function testMultiUsernameFilterFrom( $input, $expected ) {
+ $filter = $this->makeMultiUsernameFilter();
+ $result = $filter->filterFromForm( $input );
+ self::assertSame( $expected, $result );
+ }
+
+ public function provideMultiUsernameFilterFrom() {
+ return [
+ [ '', null ],
+ [ "\n\n\n", null ],
+ [ 'Foo', '1' ],
+ [ "\n\n\nFoo\nBar\n", "1\n2" ],
+ [ "Baz\nInvalid\nFoo", "3\n1" ],
+ [ "Invalid", null ],
+ [ "Invalid\n\n\nInvalid\n", null ],
+ ];
+ }
+
+ /**
+ * @covers MediaWiki\Preferences\MultiUsernameFilter::filterForForm()
+ * @dataProvider provideMultiUsernameFilterFor
+ *
+ * @param string $input
+ * @param string $expected
+ */
+ public function testMultiUsernameFilterFor( $input, $expected ) {
+ $filter = $this->makeMultiUsernameFilter();
+ $result = $filter->filterForForm( $input );
+ self::assertSame( $expected, $result );
+ }
+
+ public function provideMultiUsernameFilterFor() {
+ return [
+ [ '', '' ],
+ [ "\n", '' ],
+ [ '1', 'Foo' ],
+ [ "\n1\n\n2\377\n", "Foo\nBar" ],
+ [ "666\n667", '' ],
+ ];
+ }
+
+ private function makeMultiUsernameFilter() {
+ $userMapping = [
+ 'Foo' => 1,
+ 'Bar' => 2,
+ 'Baz' => 3,
+ ];
+ $flipped = array_flip( $userMapping );
+ $idLookup = self::getMockBuilder( CentralIdLookup::class )
+ ->disableOriginalConstructor()
+ ->setMethods( [ 'centralIdsFromNames', 'namesFromCentralIds' ] )
+ ->getMockForAbstractClass();
+
+ $idLookup->method( 'centralIdsFromNames' )
+ ->will( self::returnCallback( function ( $names ) use ( $userMapping ) {
+ $ids = [];
+ foreach ( $names as $name ) {
+ $ids[] = $userMapping[$name] ?? null;
+ }
+ return array_filter( $ids, 'is_numeric' );
+ } ) );
+ $idLookup->method( 'namesFromCentralIds' )
+ ->will( self::returnCallback( function ( $ids ) use ( $flipped ) {
+ $names = [];
+ foreach ( $ids as $id ) {
+ $names[] = $flipped[$id] ?? null;
+ }
+ return array_filter( $names, 'is_string' );
+ } ) );
+
+ return new MultiUsernameFilter( $idLookup );
+ }
+}
--- /dev/null
+<?php
+
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * @covers ExtensionProcessor
+ */
+class ExtensionProcessorTest extends \MediaWikiUnitTestCase {
+
+ private $dir, $dirname;
+
+ public function setUp() {
+ parent::setUp();
+ $this->dir = __DIR__ . '/FooBar/extension.json';
+ $this->dirname = dirname( $this->dir );
+ }
+
+ /**
+ * 'name' is absolutely required
+ *
+ * @var array
+ */
+ public static $default = [
+ 'name' => 'FooBar',
+ ];
+
+ public function testExtractInfo() {
+ // Test that attributes that begin with @ are ignored
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, self::$default + [
+ '@metadata' => [ 'foobarbaz' ],
+ 'AnAttribute' => [ 'omg' ],
+ 'AutoloadClasses' => [ 'FooBar' => 'includes/FooBar.php' ],
+ 'SpecialPages' => [ 'Foo' => 'SpecialFoo' ],
+ 'callback' => 'FooBar::onRegistration',
+ ], 1 );
+
+ $extracted = $processor->getExtractedInfo();
+ $attributes = $extracted['attributes'];
+ $this->assertArrayHasKey( 'AnAttribute', $attributes );
+ $this->assertArrayNotHasKey( '@metadata', $attributes );
+ $this->assertArrayNotHasKey( 'AutoloadClasses', $attributes );
+ $this->assertSame(
+ [ 'FooBar' => 'FooBar::onRegistration' ],
+ $extracted['callbacks']
+ );
+ $this->assertSame(
+ [ 'Foo' => 'SpecialFoo' ],
+ $extracted['globals']['wgSpecialPages']
+ );
+ }
+
+ public function testExtractNamespaces() {
+ // Test that namespace IDs can be overwritten
+ if ( !defined( 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X' ) ) {
+ define( 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X', 123456 );
+ }
+
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, self::$default + [
+ 'namespaces' => [
+ [
+ 'id' => 332200,
+ 'constant' => 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A',
+ 'name' => 'Test_A',
+ 'defaultcontentmodel' => 'TestModel',
+ 'gender' => [
+ 'male' => 'Male test',
+ 'female' => 'Female test',
+ ],
+ 'subpages' => true,
+ 'content' => true,
+ 'protection' => 'userright',
+ ],
+ [ // Test_X will use ID 123456 not 334400
+ 'id' => 334400,
+ 'constant' => 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X',
+ 'name' => 'Test_X',
+ 'defaultcontentmodel' => 'TestModel'
+ ],
+ ]
+ ], 1 );
+
+ $extracted = $processor->getExtractedInfo();
+
+ $this->assertArrayHasKey(
+ 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A',
+ $extracted['defines']
+ );
+ $this->assertArrayNotHasKey(
+ 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X',
+ $extracted['defines']
+ );
+
+ $this->assertSame(
+ $extracted['defines']['MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A'],
+ 332200
+ );
+
+ $this->assertArrayHasKey( 'ExtensionNamespaces', $extracted['attributes'] );
+ $this->assertArrayHasKey( 123456, $extracted['attributes']['ExtensionNamespaces'] );
+ $this->assertArrayHasKey( 332200, $extracted['attributes']['ExtensionNamespaces'] );
+ $this->assertArrayNotHasKey( 334400, $extracted['attributes']['ExtensionNamespaces'] );
+
+ $this->assertSame( 'Test_X', $extracted['attributes']['ExtensionNamespaces'][123456] );
+ $this->assertSame( 'Test_A', $extracted['attributes']['ExtensionNamespaces'][332200] );
+ $this->assertSame(
+ [ 'male' => 'Male test', 'female' => 'Female test' ],
+ $extracted['globals']['wgExtraGenderNamespaces'][332200]
+ );
+ // A has subpages, X does not
+ $this->assertTrue( $extracted['globals']['wgNamespacesWithSubpages'][332200] );
+ $this->assertArrayNotHasKey( 123456, $extracted['globals']['wgNamespacesWithSubpages'] );
+ }
+
+ public static function provideRegisterHooks() {
+ $merge = [ ExtensionRegistry::MERGE_STRATEGY => 'array_merge_recursive' ];
+ // Format:
+ // Current $wgHooks
+ // Content in extension.json
+ // Expected value of $wgHooks
+ return [
+ // No hooks
+ [
+ [],
+ self::$default,
+ $merge,
+ ],
+ // No current hooks, adding one for "FooBaz" in string format
+ [
+ [],
+ [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
+ [ 'FooBaz' => [ 'FooBazCallback' ] ] + $merge,
+ ],
+ // Hook for "FooBaz", adding another one
+ [
+ [ 'FooBaz' => [ 'PriorCallback' ] ],
+ [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
+ [ 'FooBaz' => [ 'PriorCallback', 'FooBazCallback' ] ] + $merge,
+ ],
+ // No current hooks, adding one for "FooBaz" in verbose array format
+ [
+ [],
+ [ 'Hooks' => [ 'FooBaz' => [ 'FooBazCallback' ] ] ] + self::$default,
+ [ 'FooBaz' => [ 'FooBazCallback' ] ] + $merge,
+ ],
+ // Hook for "BarBaz", adding one for "FooBaz"
+ [
+ [ 'BarBaz' => [ 'BarBazCallback' ] ],
+ [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
+ [
+ 'BarBaz' => [ 'BarBazCallback' ],
+ 'FooBaz' => [ 'FooBazCallback' ],
+ ] + $merge,
+ ],
+ // Callbacks for FooBaz wrapped in an array
+ [
+ [],
+ [ 'Hooks' => [ 'FooBaz' => [ 'Callback1' ] ] ] + self::$default,
+ [
+ 'FooBaz' => [ 'Callback1' ],
+ ] + $merge,
+ ],
+ // Multiple callbacks for FooBaz hook
+ [
+ [],
+ [ 'Hooks' => [ 'FooBaz' => [ 'Callback1', 'Callback2' ] ] ] + self::$default,
+ [
+ 'FooBaz' => [ 'Callback1', 'Callback2' ],
+ ] + $merge,
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideRegisterHooks
+ */
+ public function testRegisterHooks( $pre, $info, $expected ) {
+ $processor = new MockExtensionProcessor( [ 'wgHooks' => $pre ] );
+ $processor->extractInfo( $this->dir, $info, 1 );
+ $extracted = $processor->getExtractedInfo();
+ $this->assertEquals( $expected, $extracted['globals']['wgHooks'] );
+ }
+
+ public function testExtractConfig1() {
+ $processor = new ExtensionProcessor;
+ $info = [
+ 'config' => [
+ 'Bar' => 'somevalue',
+ 'Foo' => 10,
+ '@IGNORED' => 'yes',
+ ],
+ ] + self::$default;
+ $info2 = [
+ 'config' => [
+ '_prefix' => 'eg',
+ 'Bar' => 'somevalue'
+ ],
+ 'name' => 'FooBar2',
+ ];
+ $processor->extractInfo( $this->dir, $info, 1 );
+ $processor->extractInfo( $this->dir, $info2, 1 );
+ $extracted = $processor->getExtractedInfo();
+ $this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
+ $this->assertEquals( 10, $extracted['globals']['wgFoo'] );
+ $this->assertArrayNotHasKey( 'wg@IGNORED', $extracted['globals'] );
+ // Custom prefix:
+ $this->assertEquals( 'somevalue', $extracted['globals']['egBar'] );
+ }
+
+ public function testExtractConfig2() {
+ $processor = new ExtensionProcessor;
+ $info = [
+ 'config' => [
+ 'Bar' => [ 'value' => 'somevalue' ],
+ 'Foo' => [ 'value' => 10 ],
+ 'Path' => [ 'value' => 'foo.txt', 'path' => true ],
+ 'Namespaces' => [
+ 'value' => [
+ '10' => true,
+ '12' => false,
+ ],
+ 'merge_strategy' => 'array_plus',
+ ],
+ ],
+ ] + self::$default;
+ $info2 = [
+ 'config' => [
+ 'Bar' => [ 'value' => 'somevalue' ],
+ ],
+ 'config_prefix' => 'eg',
+ 'name' => 'FooBar2',
+ ];
+ $processor->extractInfo( $this->dir, $info, 2 );
+ $processor->extractInfo( $this->dir, $info2, 2 );
+ $extracted = $processor->getExtractedInfo();
+ $this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
+ $this->assertEquals( 10, $extracted['globals']['wgFoo'] );
+ $this->assertEquals( "{$this->dirname}/foo.txt", $extracted['globals']['wgPath'] );
+ // Custom prefix:
+ $this->assertEquals( 'somevalue', $extracted['globals']['egBar'] );
+ $this->assertSame(
+ [ 10 => true, 12 => false, ExtensionRegistry::MERGE_STRATEGY => 'array_plus' ],
+ $extracted['globals']['wgNamespaces']
+ );
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testDuplicateConfigKey1() {
+ $processor = new ExtensionProcessor;
+ $info = [
+ 'config' => [
+ 'Bar' => '',
+ ]
+ ] + self::$default;
+ $info2 = [
+ 'config' => [
+ 'Bar' => 'g',
+ ],
+ 'name' => 'FooBar2',
+ ];
+ $processor->extractInfo( $this->dir, $info, 1 );
+ $processor->extractInfo( $this->dir, $info2, 1 );
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testDuplicateConfigKey2() {
+ $processor = new ExtensionProcessor;
+ $info = [
+ 'config' => [
+ 'Bar' => [ 'value' => 'somevalue' ],
+ ]
+ ] + self::$default;
+ $info2 = [
+ 'config' => [
+ 'Bar' => [ 'value' => 'somevalue' ],
+ ],
+ 'name' => 'FooBar2',
+ ];
+ $processor->extractInfo( $this->dir, $info, 2 );
+ $processor->extractInfo( $this->dir, $info2, 2 );
+ }
+
+ public static function provideExtractExtensionMessagesFiles() {
+ $dir = __DIR__ . '/FooBar/';
+ return [
+ [
+ [ 'ExtensionMessagesFiles' => [ 'FooBarAlias' => 'FooBar.alias.php' ] ],
+ [ 'wgExtensionMessagesFiles' => [ 'FooBarAlias' => $dir . 'FooBar.alias.php' ] ]
+ ],
+ [
+ [
+ 'ExtensionMessagesFiles' => [
+ 'FooBarAlias' => 'FooBar.alias.php',
+ 'FooBarMagic' => 'FooBar.magic.i18n.php',
+ ],
+ ],
+ [
+ 'wgExtensionMessagesFiles' => [
+ 'FooBarAlias' => $dir . 'FooBar.alias.php',
+ 'FooBarMagic' => $dir . 'FooBar.magic.i18n.php',
+ ],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideExtractExtensionMessagesFiles
+ */
+ public function testExtractExtensionMessagesFiles( $input, $expected ) {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
+ $out = $processor->getExtractedInfo();
+ foreach ( $expected as $key => $value ) {
+ $this->assertEquals( $value, $out['globals'][$key] );
+ }
+ }
+
+ public static function provideExtractMessagesDirs() {
+ $dir = __DIR__ . '/FooBar/';
+ return [
+ [
+ [ 'MessagesDirs' => [ 'VisualEditor' => 'i18n' ] ],
+ [ 'wgMessagesDirs' => [ 'VisualEditor' => [ $dir . 'i18n' ] ] ]
+ ],
+ [
+ [ 'MessagesDirs' => [ 'VisualEditor' => [ 'i18n', 'foobar' ] ] ],
+ [ 'wgMessagesDirs' => [ 'VisualEditor' => [ $dir . 'i18n', $dir . 'foobar' ] ] ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideExtractMessagesDirs
+ */
+ public function testExtractMessagesDirs( $input, $expected ) {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
+ $out = $processor->getExtractedInfo();
+ foreach ( $expected as $key => $value ) {
+ $this->assertEquals( $value, $out['globals'][$key] );
+ }
+ }
+
+ public function testExtractCredits() {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, self::$default, 1 );
+ $this->setExpectedException( Exception::class );
+ $processor->extractInfo( $this->dir, self::$default, 1 );
+ }
+
+ /**
+ * @dataProvider provideExtractResourceLoaderModules
+ */
+ public function testExtractResourceLoaderModules(
+ $input,
+ array $expectedGlobals,
+ array $expectedAttribs = []
+ ) {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
+ $out = $processor->getExtractedInfo();
+ foreach ( $expectedGlobals as $key => $value ) {
+ $this->assertEquals( $value, $out['globals'][$key] );
+ }
+ foreach ( $expectedAttribs as $key => $value ) {
+ $this->assertEquals( $value, $out['attributes'][$key] );
+ }
+ }
+
+ public static function provideExtractResourceLoaderModules() {
+ $dir = __DIR__ . '/FooBar';
+ return [
+ // Generic module with localBasePath/remoteExtPath specified
+ [
+ // Input
+ [
+ 'ResourceModules' => [
+ 'test.foo' => [
+ 'styles' => 'foobar.js',
+ 'localBasePath' => '',
+ 'remoteExtPath' => 'FooBar',
+ ],
+ ],
+ ],
+ // Expected
+ [
+ 'wgResourceModules' => [
+ 'test.foo' => [
+ 'styles' => 'foobar.js',
+ 'localBasePath' => $dir,
+ 'remoteExtPath' => 'FooBar',
+ ],
+ ],
+ ],
+ ],
+ // ResourceFileModulePaths specified:
+ [
+ // Input
+ [
+ 'ResourceFileModulePaths' => [
+ 'localBasePath' => 'modules',
+ 'remoteExtPath' => 'FooBar/modules',
+ ],
+ 'ResourceModules' => [
+ // No paths
+ 'test.foo' => [
+ 'styles' => 'foo.js',
+ ],
+ // Different paths set
+ 'test.bar' => [
+ 'styles' => 'bar.js',
+ 'localBasePath' => 'subdir',
+ 'remoteExtPath' => 'FooBar/subdir',
+ ],
+ // Custom class with no paths set
+ 'test.class' => [
+ 'class' => 'FooBarModule',
+ 'extra' => 'argument',
+ ],
+ // Custom class with a localBasePath
+ 'test.class.with.path' => [
+ 'class' => 'FooBarPathModule',
+ 'extra' => 'argument',
+ 'localBasePath' => '',
+ ]
+ ],
+ ],
+ // Expected
+ [
+ 'wgResourceModules' => [
+ 'test.foo' => [
+ 'styles' => 'foo.js',
+ 'localBasePath' => "$dir/modules",
+ 'remoteExtPath' => 'FooBar/modules',
+ ],
+ 'test.bar' => [
+ 'styles' => 'bar.js',
+ 'localBasePath' => "$dir/subdir",
+ 'remoteExtPath' => 'FooBar/subdir',
+ ],
+ 'test.class' => [
+ 'class' => 'FooBarModule',
+ 'extra' => 'argument',
+ 'localBasePath' => "$dir/modules",
+ 'remoteExtPath' => 'FooBar/modules',
+ ],
+ 'test.class.with.path' => [
+ 'class' => 'FooBarPathModule',
+ 'extra' => 'argument',
+ 'localBasePath' => $dir,
+ 'remoteExtPath' => 'FooBar/modules',
+ ]
+ ],
+ ],
+ ],
+ // ResourceModuleSkinStyles with file module paths
+ [
+ // Input
+ [
+ 'ResourceFileModulePaths' => [
+ 'localBasePath' => '',
+ 'remoteSkinPath' => 'FooBar',
+ ],
+ 'ResourceModuleSkinStyles' => [
+ 'foobar' => [
+ 'test.foo' => 'foo.css',
+ ]
+ ],
+ ],
+ // Expected
+ [
+ 'wgResourceModuleSkinStyles' => [
+ 'foobar' => [
+ 'test.foo' => 'foo.css',
+ 'localBasePath' => $dir,
+ 'remoteSkinPath' => 'FooBar',
+ ],
+ ],
+ ],
+ ],
+ // ResourceModuleSkinStyles with file module paths and an override
+ [
+ // Input
+ [
+ 'ResourceFileModulePaths' => [
+ 'localBasePath' => '',
+ 'remoteSkinPath' => 'FooBar',
+ ],
+ 'ResourceModuleSkinStyles' => [
+ 'foobar' => [
+ 'test.foo' => 'foo.css',
+ 'remoteSkinPath' => 'BarFoo'
+ ],
+ ],
+ ],
+ // Expected
+ [
+ 'wgResourceModuleSkinStyles' => [
+ 'foobar' => [
+ 'test.foo' => 'foo.css',
+ 'localBasePath' => $dir,
+ 'remoteSkinPath' => 'BarFoo',
+ ],
+ ],
+ ],
+ ],
+ 'QUnit test module' => [
+ // Input
+ [
+ 'QUnitTestModule' => [
+ 'localBasePath' => '',
+ 'remoteExtPath' => 'Foo',
+ 'scripts' => 'bar.js',
+ ],
+ ],
+ // Expected
+ [],
+ [
+ 'QUnitTestModules' => [
+ 'test.FooBar' => [
+ 'localBasePath' => $dir,
+ 'remoteExtPath' => 'Foo',
+ 'scripts' => 'bar.js',
+ ],
+ ],
+ ],
+ ],
+ ];
+ }
+
+ public static function provideSetToGlobal() {
+ return [
+ [
+ [ 'wgAPIModules', 'wgAvailableRights' ],
+ [],
+ [
+ 'APIModules' => [ 'foobar' => 'ApiFooBar' ],
+ 'AvailableRights' => [ 'foobar', 'unfoobar' ],
+ ],
+ [
+ 'wgAPIModules' => [ 'foobar' => 'ApiFooBar' ],
+ 'wgAvailableRights' => [ 'foobar', 'unfoobar' ],
+ ],
+ ],
+ [
+ [ 'wgAPIModules', 'wgAvailableRights' ],
+ [
+ 'wgAPIModules' => [ 'barbaz' => 'ApiBarBaz' ],
+ 'wgAvailableRights' => [ 'barbaz' ]
+ ],
+ [
+ 'APIModules' => [ 'foobar' => 'ApiFooBar' ],
+ 'AvailableRights' => [ 'foobar', 'unfoobar' ],
+ ],
+ [
+ 'wgAPIModules' => [ 'barbaz' => 'ApiBarBaz', 'foobar' => 'ApiFooBar' ],
+ 'wgAvailableRights' => [ 'barbaz', 'foobar', 'unfoobar' ],
+ ],
+ ],
+ [
+ [ 'wgGroupPermissions' ],
+ [
+ 'wgGroupPermissions' => [
+ 'sysop' => [ 'delete' ]
+ ],
+ ],
+ [
+ 'GroupPermissions' => [
+ 'sysop' => [ 'undelete' ],
+ 'user' => [ 'edit' ]
+ ],
+ ],
+ [
+ 'wgGroupPermissions' => [
+ 'sysop' => [ 'delete', 'undelete' ],
+ 'user' => [ 'edit' ]
+ ],
+ ]
+ ]
+ ];
+ }
+
+ /**
+ * Attributes under manifest_version 2
+ */
+ public function testExtractAttributes() {
+ $processor = new ExtensionProcessor();
+ // Load FooBar extension
+ $processor->extractInfo( $this->dir, [ 'name' => 'FooBar' ], 2 );
+ $processor->extractInfo(
+ $this->dir,
+ [
+ 'name' => 'Baz',
+ 'attributes' => [
+ // Loaded
+ 'FooBar' => [
+ 'Plugins' => [
+ 'ext.baz.foobar',
+ ],
+ ],
+ // Not loaded
+ 'FizzBuzz' => [
+ 'MorePlugins' => [
+ 'ext.baz.fizzbuzz',
+ ],
+ ],
+ ],
+ ],
+ 2
+ );
+
+ $info = $processor->getExtractedInfo();
+ $this->assertArrayHasKey( 'FooBarPlugins', $info['attributes'] );
+ $this->assertSame( [ 'ext.baz.foobar' ], $info['attributes']['FooBarPlugins'] );
+ $this->assertArrayNotHasKey( 'FizzBuzzMorePlugins', $info['attributes'] );
+ }
+
+ /**
+ * Attributes under manifest_version 1
+ */
+ public function testAttributes1() {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo(
+ $this->dir,
+ [
+ 'name' => 'FooBar',
+ 'FooBarPlugins' => [
+ 'ext.baz.foobar',
+ ],
+ 'FizzBuzzMorePlugins' => [
+ 'ext.baz.fizzbuzz',
+ ],
+ ],
+ 1
+ );
+ $processor->extractInfo(
+ $this->dir,
+ [
+ 'name' => 'FooBar2',
+ 'FizzBuzzMorePlugins' => [
+ 'ext.bar.fizzbuzz',
+ ]
+ ],
+ 1
+ );
+
+ $info = $processor->getExtractedInfo();
+ $this->assertArrayHasKey( 'FooBarPlugins', $info['attributes'] );
+ $this->assertSame( [ 'ext.baz.foobar' ], $info['attributes']['FooBarPlugins'] );
+ $this->assertArrayHasKey( 'FizzBuzzMorePlugins', $info['attributes'] );
+ $this->assertSame(
+ [ 'ext.baz.fizzbuzz', 'ext.bar.fizzbuzz' ],
+ $info['attributes']['FizzBuzzMorePlugins']
+ );
+ }
+
+ public function testAttributes1_notarray() {
+ $processor = new ExtensionProcessor();
+ $this->setExpectedException(
+ InvalidArgumentException::class,
+ "The value for 'FooBarPlugins' should be an array (from {$this->dir})"
+ );
+ $processor->extractInfo(
+ $this->dir,
+ [
+ 'FooBarPlugins' => 'ext.baz.foobar',
+ ] + self::$default,
+ 1
+ );
+ }
+
+ public function testExtractPathBasedGlobal() {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo(
+ $this->dir,
+ [
+ 'ParserTestFiles' => [
+ 'tests/parserTests.txt',
+ 'tests/extraParserTests.txt',
+ ],
+ 'ServiceWiringFiles' => [
+ 'includes/ServiceWiring.php'
+ ],
+ ] + self::$default,
+ 1
+ );
+ $globals = $processor->getExtractedInfo()['globals'];
+ $this->assertArrayHasKey( 'wgParserTestFiles', $globals );
+ $this->assertSame( [
+ "{$this->dirname}/tests/parserTests.txt",
+ "{$this->dirname}/tests/extraParserTests.txt"
+ ], $globals['wgParserTestFiles'] );
+ $this->assertArrayHasKey( 'wgServiceWiringFiles', $globals );
+ $this->assertSame( [
+ "{$this->dirname}/includes/ServiceWiring.php"
+ ], $globals['wgServiceWiringFiles'] );
+ }
+
+ public function testGetRequirements() {
+ $info = self::$default + [
+ 'requires' => [
+ 'MediaWiki' => '>= 1.25.0',
+ 'platform' => [
+ 'php' => '>= 5.5.9'
+ ],
+ 'extensions' => [
+ 'Bar' => '*'
+ ]
+ ]
+ ];
+ $processor = new ExtensionProcessor();
+ $this->assertSame(
+ $info['requires'],
+ $processor->getRequirements( $info, false )
+ );
+ $this->assertSame(
+ [],
+ $processor->getRequirements( [], false )
+ );
+ }
+
+ public function testGetDevRequirements() {
+ $info = self::$default + [
+ 'dev-requires' => [
+ 'MediaWiki' => '>= 1.31.0',
+ 'platform' => [
+ 'ext-foo' => '*',
+ ],
+ 'skins' => [
+ 'Baz' => '*',
+ ],
+ 'extensions' => [
+ 'Biz' => '*',
+ ],
+ ],
+ ];
+ $processor = new ExtensionProcessor();
+ $this->assertSame(
+ $info['dev-requires'],
+ $processor->getRequirements( $info, true )
+ );
+ // Set some standard requirements, so we can test merging
+ $info['requires'] = [
+ 'MediaWiki' => '>= 1.25.0',
+ 'platform' => [
+ 'php' => '>= 5.5.9'
+ ],
+ 'extensions' => [
+ 'Bar' => '*'
+ ]
+ ];
+ $this->assertSame(
+ [
+ 'MediaWiki' => '>= 1.25.0 >= 1.31.0',
+ 'platform' => [
+ 'php' => '>= 5.5.9',
+ 'ext-foo' => '*',
+ ],
+ 'extensions' => [
+ 'Bar' => '*',
+ 'Biz' => '*',
+ ],
+ 'skins' => [
+ 'Baz' => '*',
+ ],
+ ],
+ $processor->getRequirements( $info, true )
+ );
+
+ // If there's no dev-requires, it just returns requires
+ unset( $info['dev-requires'] );
+ $this->assertSame(
+ $info['requires'],
+ $processor->getRequirements( $info, true )
+ );
+ }
+
+ public function testGetExtraAutoloaderPaths() {
+ $processor = new ExtensionProcessor();
+ $this->assertSame(
+ [ "{$this->dirname}/vendor/autoload.php" ],
+ $processor->getExtraAutoloaderPaths( $this->dirname, [
+ 'load_composer_autoloader' => true,
+ ] )
+ );
+ }
+
+ /**
+ * Verify that extension.schema.json is in sync with ExtensionProcessor
+ *
+ * @coversNothing
+ */
+ public function testGlobalSettingsDocumentedInSchema() {
+ global $IP;
+ $globalSettings = TestingAccessWrapper::newFromClass(
+ ExtensionProcessor::class )->globalSettings;
+
+ $version = ExtensionRegistry::MANIFEST_VERSION;
+ $schema = FormatJson::decode(
+ file_get_contents( "$IP/docs/extension.schema.v$version.json" ),
+ true
+ );
+ $missing = [];
+ foreach ( $globalSettings as $global ) {
+ if ( !isset( $schema['properties'][$global] ) ) {
+ $missing[] = $global;
+ }
+ }
+
+ $this->assertEquals( [], $missing,
+ "The following global settings are not documented in docs/extension.schema.json" );
+ }
+}
+
+/**
+ * Allow overriding the default value of $this->globals
+ * so we can test merging
+ */
+class MockExtensionProcessor extends ExtensionProcessor {
+ public function __construct( $globals = [] ) {
+ $this->globals = $globals + $this->globals;
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group Search
+ * @covers SearchIndexFieldDefinition
+ */
+class SearchIndexFieldTest extends \MediaWikiUnitTestCase {
+
+ public function getMergeCases() {
+ return [
+ [ 0, 'test', 0, 'test', true ],
+ [ SearchIndexField::INDEX_TYPE_NESTED, 'test',
+ SearchIndexField::INDEX_TYPE_NESTED, 'test', false ],
+ [ 0, 'test', 0, 'test2', true ],
+ [ 0, 'test', 1, 'test', false ],
+ ];
+ }
+
+ /**
+ * @dataProvider getMergeCases
+ * @param int $t1
+ * @param string $n1
+ * @param int $t2
+ * @param string $n2
+ * @param bool $result
+ */
+ public function testMerge( $t1, $n1, $t2, $n2, $result ) {
+ $field1 =
+ $this->getMockBuilder( SearchIndexFieldDefinition::class )
+ ->setMethods( [ 'getMapping' ] )
+ ->setConstructorArgs( [ $n1, $t1 ] )
+ ->getMock();
+ $field2 =
+ $this->getMockBuilder( SearchIndexFieldDefinition::class )
+ ->setMethods( [ 'getMapping' ] )
+ ->setConstructorArgs( [ $n2, $t2 ] )
+ ->getMock();
+
+ if ( $result ) {
+ $this->assertNotFalse( $field1->merge( $field2 ) );
+ } else {
+ $this->assertFalse( $field1->merge( $field2 ) );
+ }
+
+ $field1->setFlag( 0xFF );
+ $this->assertFalse( $field1->merge( $field2 ) );
+
+ $field1->setMergeCallback(
+ function ( $a, $b ) {
+ return "test";
+ }
+ );
+ $this->assertEquals( "test", $field1->merge( $field2 ) );
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Session;
+
+/**
+ * @group Session
+ * @covers MediaWiki\Session\MetadataMergeException
+ */
+class MetadataMergeExceptionTest extends \MediaWikiUnitTestCase {
+
+ public function testBasics() {
+ $data = [ 'foo' => 'bar' ];
+
+ $ex = new MetadataMergeException();
+ $this->assertInstanceOf( \UnexpectedValueException::class, $ex );
+ $this->assertSame( [], $ex->getContext() );
+
+ $ex2 = new MetadataMergeException( 'Message', 42, $ex, $data );
+ $this->assertSame( 'Message', $ex2->getMessage() );
+ $this->assertSame( 42, $ex2->getCode() );
+ $this->assertSame( $ex, $ex2->getPrevious() );
+ $this->assertSame( $data, $ex2->getContext() );
+
+ $ex->setContext( $data );
+ $this->assertSame( $data, $ex->getContext() );
+ }
+
+}
--- /dev/null
+<?php
+
+namespace MediaWiki\Session;
+
+/**
+ * @group Session
+ * @covers MediaWiki\Session\SessionId
+ */
+class SessionIdTest extends \MediaWikiUnitTestCase {
+
+ public function testEverything() {
+ $id = new SessionId( 'foo' );
+ $this->assertSame( 'foo', $id->getId() );
+ $this->assertSame( 'foo', (string)$id );
+ $id->setId( 'bar' );
+ $this->assertSame( 'bar', $id->getId() );
+ $this->assertSame( 'bar', (string)$id );
+ }
+
+}
--- /dev/null
+<?php
+
+class SkinFactoryTest extends \MediaWikiUnitTestCase {
+
+ /**
+ * @covers SkinFactory::register
+ */
+ public function testRegister() {
+ $factory = new SkinFactory();
+ $factory->register( 'fallback', 'Fallback', function () {
+ return new SkinFallback();
+ } );
+ $this->assertTrue( true ); // No exception thrown
+ $this->setExpectedException( InvalidArgumentException::class );
+ $factory->register( 'invalid', 'Invalid', 'Invalid callback' );
+ }
+
+ /**
+ * @covers SkinFactory::makeSkin
+ */
+ public function testMakeSkinWithNoBuilders() {
+ $factory = new SkinFactory();
+ $this->setExpectedException( SkinException::class );
+ $factory->makeSkin( 'nobuilderregistered' );
+ }
+
+ /**
+ * @covers SkinFactory::makeSkin
+ */
+ public function testMakeSkinWithInvalidCallback() {
+ $factory = new SkinFactory();
+ $factory->register( 'unittest', 'Unittest', function () {
+ return true; // Not a Skin object
+ } );
+ $this->setExpectedException( UnexpectedValueException::class );
+ $factory->makeSkin( 'unittest' );
+ }
+
+ /**
+ * @covers SkinFactory::makeSkin
+ */
+ public function testMakeSkinWithValidCallback() {
+ $factory = new SkinFactory();
+ $factory->register( 'testfallback', 'TestFallback', function () {
+ return new SkinFallback();
+ } );
+
+ $skin = $factory->makeSkin( 'testfallback' );
+ $this->assertInstanceOf( Skin::class, $skin );
+ $this->assertInstanceOf( SkinFallback::class, $skin );
+ $this->assertEquals( 'fallback', $skin->getSkinName() );
+ }
+
+ /**
+ * @covers Skin::__construct
+ * @covers Skin::getSkinName
+ */
+ public function testGetSkinName() {
+ $skin = new SkinFallback();
+ $this->assertEquals( 'fallback', $skin->getSkinName(), 'Default' );
+ $skin = new SkinFallback( 'testname' );
+ $this->assertEquals( 'testname', $skin->getSkinName(), 'Constructor argument' );
+ }
+
+ /**
+ * @covers SkinFactory::getSkinNames
+ */
+ public function testGetSkinNames() {
+ $factory = new SkinFactory();
+ // A fake callback we can use that will never be called
+ $callback = function () {
+ // NOP
+ };
+ $factory->register( 'skin1', 'Skin1', $callback );
+ $factory->register( 'skin2', 'Skin2', $callback );
+ $names = $factory->getSkinNames();
+ $this->assertArrayHasKey( 'skin1', $names );
+ $this->assertArrayHasKey( 'skin2', $names );
+ $this->assertEquals( 'Skin1', $names['skin1'] );
+ $this->assertEquals( 'Skin2', $names['skin2'] );
+ }
+}
--- /dev/null
+<?php
+/**
+ * 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
+ * @author This, that and the other
+ */
+
+/**
+ * @covers ForeignTitle
+ *
+ * @group Title
+ */
+class ForeignTitleTest extends \MediaWikiUnitTestCase {
+
+ public function basicProvider() {
+ return [
+ [
+ new ForeignTitle( 20, 'Contributor', 'JohnDoe' ),
+ 20, 'Contributor', 'JohnDoe'
+ ],
+ [
+ new ForeignTitle( '1', 'Discussion', 'Capital' ),
+ 1, 'Discussion', 'Capital'
+ ],
+ [
+ new ForeignTitle( 0, '', 'MainNamespace' ),
+ 0, '', 'MainNamespace'
+ ],
+ [
+ new ForeignTitle( 4, 'Some ns', 'Article title with spaces' ),
+ 4, 'Some_ns', 'Article_title_with_spaces'
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider basicProvider
+ */
+ public function testBasic( ForeignTitle $title, $expectedId, $expectedName,
+ $expectedText
+ ) {
+ $this->assertEquals( true, $title->isNamespaceIdKnown() );
+ $this->assertEquals( $expectedId, $title->getNamespaceId() );
+ $this->assertEquals( $expectedName, $title->getNamespaceName() );
+ $this->assertEquals( $expectedText, $title->getText() );
+ }
+
+ public function testUnknownNamespaceCheck() {
+ $title = new ForeignTitle( null, 'this', 'that' );
+
+ $this->assertEquals( false, $title->isNamespaceIdKnown() );
+ $this->assertEquals( 'this', $title->getNamespaceName() );
+ $this->assertEquals( 'that', $title->getText() );
+ }
+
+ public function testUnknownNamespaceError() {
+ $this->setExpectedException( MWException::class );
+ $title = new ForeignTitle( null, 'this', 'that' );
+ $title->getNamespaceId();
+ }
+
+ public function fullTextProvider() {
+ return [
+ [
+ new ForeignTitle( 20, 'Contributor', 'JohnDoe' ),
+ 'Contributor:JohnDoe'
+ ],
+ [
+ new ForeignTitle( '1', 'Discussion', 'Capital' ),
+ 'Discussion:Capital'
+ ],
+ [
+ new ForeignTitle( 0, '', 'MainNamespace' ),
+ 'MainNamespace'
+ ],
+ [
+ new ForeignTitle( 4, 'Some ns', 'Article title with spaces' ),
+ 'Some_ns:Article_title_with_spaces'
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider fullTextProvider
+ */
+ public function testFullText( ForeignTitle $title, $fullText ) {
+ $this->assertEquals( $fullText, $title->getFullText() );
+ }
+}
--- /dev/null
+<?php
+/**
+ * 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
+ * @author This, that and the other
+ */
+
+/**
+ * @covers NamespaceAwareForeignTitleFactory
+ *
+ * @group Title
+ */
+class NamespaceAwareForeignTitleFactoryTest extends \MediaWikiUnitTestCase {
+
+ public function basicProvider() {
+ return [
+ [
+ 'MainNamespaceArticle', 0,
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ ],
+ [
+ 'MainNamespaceArticle', null,
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ ],
+ [
+ 'Magic:_The_Gathering', 0,
+ new ForeignTitle( 0, '', 'Magic:_The_Gathering' ),
+ ],
+ [
+ 'Talk:Nice_talk', 1,
+ new ForeignTitle( 1, 'Talk', 'Nice_talk' ),
+ ],
+ [
+ 'Talk:Magic:_The_Gathering', 1,
+ new ForeignTitle( 1, 'Talk', 'Magic:_The_Gathering' ),
+ ],
+ [
+ 'Bogus:Nice_talk', 0,
+ new ForeignTitle( 0, '', 'Bogus:Nice_talk' ),
+ ],
+ [
+ 'Bogus:Nice_talk', null,
+ new ForeignTitle( 9000, 'Bogus', 'Nice_talk' ),
+ ],
+ [
+ 'Bogus:Nice_talk', 4,
+ new ForeignTitle( 4, 'Bogus', 'Nice_talk' ),
+ ],
+ [
+ 'Bogus:Nice_talk', 1,
+ new ForeignTitle( 1, 'Talk', 'Nice_talk' ),
+ ],
+ // Misconfigured wiki with unregistered namespace (T114115)
+ [
+ 'Nice_talk', 1234,
+ new ForeignTitle( 1234, 'Ns1234', 'Nice_talk' ),
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider basicProvider
+ */
+ public function testBasic( $title, $ns, ForeignTitle $foreignTitle ) {
+ $foreignNamespaces = [
+ 0 => '', 1 => 'Talk', 100 => 'Portal', 9000 => 'Bogus'
+ ];
+
+ $factory = new NamespaceAwareForeignTitleFactory( $foreignNamespaces );
+ $testTitle = $factory->createForeignTitle( $title, $ns );
+
+ $this->assertEquals( $testTitle->isNamespaceIdKnown(),
+ $foreignTitle->isNamespaceIdKnown() );
+
+ if (
+ $testTitle->isNamespaceIdKnown() &&
+ $foreignTitle->isNamespaceIdKnown()
+ ) {
+ $this->assertEquals( $testTitle->getNamespaceId(),
+ $foreignTitle->getNamespaceId() );
+ }
+
+ $this->assertEquals( $testTitle->getNamespaceName(),
+ $foreignTitle->getNamespaceName() );
+ $this->assertEquals( $testTitle->getText(), $foreignTitle->getText() );
+ }
+}
--- /dev/null
+<?php
+/**
+ * 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
+ * @author Daniel Kinzler
+ */
+
+/**
+ * @covers TitleValue
+ *
+ * @group Title
+ */
+class TitleValueTest extends \MediaWikiUnitTestCase {
+
+ public function goodConstructorProvider() {
+ return [
+ [ NS_MAIN, '', 'fragment', '', true, false ],
+ [ NS_USER, 'TestThis', 'stuff', '', true, false ],
+ [ NS_USER, 'TestThis', '', 'baz', false, true ],
+ ];
+ }
+
+ /**
+ * @dataProvider goodConstructorProvider
+ */
+ public function testConstruction( $ns, $text, $fragment, $interwiki, $hasFragment,
+ $hasInterwiki
+ ) {
+ $title = new TitleValue( $ns, $text, $fragment, $interwiki );
+
+ $this->assertEquals( $ns, $title->getNamespace() );
+ $this->assertTrue( $title->inNamespace( $ns ) );
+ $this->assertEquals( $text, $title->getText() );
+ $this->assertEquals( $fragment, $title->getFragment() );
+ $this->assertEquals( $hasFragment, $title->hasFragment() );
+ $this->assertEquals( $interwiki, $title->getInterwiki() );
+ $this->assertEquals( $hasInterwiki, $title->isExternal() );
+ }
+
+ public function badConstructorProvider() {
+ return [
+ [ 'foo', 'title', 'fragment', '' ],
+ [ null, 'title', 'fragment', '' ],
+ [ 2.3, 'title', 'fragment', '' ],
+
+ [ NS_MAIN, 5, 'fragment', '' ],
+ [ NS_MAIN, null, 'fragment', '' ],
+ [ NS_USER, '', 'fragment', '' ],
+ [ NS_MAIN, 'foo bar', '', '' ],
+ [ NS_MAIN, 'bar_', '', '' ],
+ [ NS_MAIN, '_foo', '', '' ],
+ [ NS_MAIN, ' eek ', '', '' ],
+
+ [ NS_MAIN, 'title', 5, '' ],
+ [ NS_MAIN, 'title', null, '' ],
+ [ NS_MAIN, 'title', [], '' ],
+
+ [ NS_MAIN, 'title', '', 5 ],
+ [ NS_MAIN, 'title', null, 5 ],
+ [ NS_MAIN, 'title', [], 5 ],
+ ];
+ }
+
+ /**
+ * @dataProvider badConstructorProvider
+ */
+ public function testConstructionErrors( $ns, $text, $fragment, $interwiki ) {
+ $this->setExpectedException( InvalidArgumentException::class );
+ new TitleValue( $ns, $text, $fragment, $interwiki );
+ }
+
+ public function fragmentTitleProvider() {
+ return [
+ [ new TitleValue( NS_MAIN, 'Test' ), 'foo' ],
+ [ new TitleValue( NS_TALK, 'Test', 'foo' ), '' ],
+ [ new TitleValue( NS_CATEGORY, 'Test', 'foo' ), 'bar' ],
+ ];
+ }
+
+ /**
+ * @dataProvider fragmentTitleProvider
+ */
+ public function testCreateFragmentTitle( TitleValue $title, $fragment ) {
+ $fragmentTitle = $title->createFragmentTarget( $fragment );
+
+ $this->assertEquals( $title->getNamespace(), $fragmentTitle->getNamespace() );
+ $this->assertEquals( $title->getText(), $fragmentTitle->getText() );
+ $this->assertEquals( $fragment, $fragmentTitle->getFragment() );
+ }
+
+ public function getTextProvider() {
+ return [
+ [ 'Foo', 'Foo' ],
+ [ 'Foo_Bar', 'Foo Bar' ],
+ ];
+ }
+
+ /**
+ * @dataProvider getTextProvider
+ */
+ public function testGetText( $dbkey, $text ) {
+ $title = new TitleValue( NS_MAIN, $dbkey );
+
+ $this->assertEquals( $text, $title->getText() );
+ }
+
+ public function provideTestToString() {
+ yield [
+ new TitleValue( 0, 'Foo' ),
+ '0:Foo'
+ ];
+ yield [
+ new TitleValue( 1, 'Bar_Baz' ),
+ '1:Bar_Baz'
+ ];
+ yield [
+ new TitleValue( 9, 'JoJo', 'Frag' ),
+ '9:JoJo#Frag'
+ ];
+ yield [
+ new TitleValue( 200, 'tea', 'Fragment', 'wikicode' ),
+ 'wikicode:200:tea#Fragment'
+ ];
+ }
+
+ /**
+ * @dataProvider provideTestToString
+ */
+ public function testToString( TitleValue $value, $expected ) {
+ $this->assertSame(
+ $expected,
+ $value->__toString()
+ );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @author Addshore
+ * @covers UserArrayFromResult
+ */
+class UserArrayFromResultTest extends \MediaWikiUnitTestCase {
+
+ private function getMockResultWrapper( $row = null, $numRows = 1 ) {
+ $resultWrapper = $this->getMockBuilder( Wikimedia\Rdbms\ResultWrapper::class )
+ ->disableOriginalConstructor();
+
+ $resultWrapper = $resultWrapper->getMock();
+ $resultWrapper->expects( $this->atLeastOnce() )
+ ->method( 'current' )
+ ->will( $this->returnValue( $row ) );
+ $resultWrapper->expects( $this->any() )
+ ->method( 'numRows' )
+ ->will( $this->returnValue( $numRows ) );
+
+ return $resultWrapper;
+ }
+
+ private function getRowWithUsername( $username = 'fooUser' ) {
+ $row = new stdClass();
+ $row->user_name = $username;
+ return $row;
+ }
+
+ /**
+ * @covers UserArrayFromResult::__construct
+ */
+ public function testConstructionWithFalseRow() {
+ $row = false;
+ $resultWrapper = $this->getMockResultWrapper( $row );
+
+ $object = new UserArrayFromResult( $resultWrapper );
+
+ $this->assertEquals( $resultWrapper, $object->res );
+ $this->assertSame( 0, $object->key );
+ $this->assertEquals( $row, $object->current );
+ }
+
+ /**
+ * @covers UserArrayFromResult::__construct
+ */
+ public function testConstructionWithRow() {
+ $username = 'addshore';
+ $row = $this->getRowWithUsername( $username );
+ $resultWrapper = $this->getMockResultWrapper( $row );
+
+ $object = new UserArrayFromResult( $resultWrapper );
+
+ $this->assertEquals( $resultWrapper, $object->res );
+ $this->assertSame( 0, $object->key );
+ $this->assertInstanceOf( User::class, $object->current );
+ $this->assertEquals( $username, $object->current->mName );
+ }
+
+ public static function provideNumberOfRows() {
+ return [
+ [ 0 ],
+ [ 1 ],
+ [ 122 ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideNumberOfRows
+ * @covers UserArrayFromResult::count
+ */
+ public function testCountWithVaryingValues( $numRows ) {
+ $object = new UserArrayFromResult( $this->getMockResultWrapper(
+ $this->getRowWithUsername(),
+ $numRows
+ ) );
+ $this->assertEquals( $numRows, $object->count() );
+ }
+
+ /**
+ * @covers UserArrayFromResult::current
+ */
+ public function testCurrentAfterConstruction() {
+ $username = 'addshore';
+ $userRow = $this->getRowWithUsername( $username );
+ $object = new UserArrayFromResult( $this->getMockResultWrapper( $userRow ) );
+ $this->assertInstanceOf( User::class, $object->current() );
+ $this->assertEquals( $username, $object->current()->mName );
+ }
+
+ public function provideTestValid() {
+ return [
+ [ $this->getRowWithUsername(), true ],
+ [ false, false ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideTestValid
+ * @covers UserArrayFromResult::valid
+ */
+ public function testValid( $input, $expected ) {
+ $object = new UserArrayFromResult( $this->getMockResultWrapper( $input ) );
+ $this->assertEquals( $expected, $object->valid() );
+ }
+
+ // @todo unit test for key()
+ // @todo unit test for next()
+ // @todo unit test for rewind()
+}
--- /dev/null
+<?php
+
+use MediaWiki\User\UserIdentityValue;
+
+/**
+ * @author Addshore
+ *
+ * @covers NoWriteWatchedItemStore
+ */
+class NoWriteWatchedItemStoreUnitTest extends \MediaWikiUnitTestCase {
+
+ public function testAddWatch() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->never() )->method( 'addWatch' );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $this->setExpectedException( DBReadOnlyError::class );
+ $noWriteService->addWatch(
+ new UserIdentityValue( 1, 'MockUser', 0 ), new TitleValue( 0, 'Foo' ) );
+ }
+
+ public function testAddWatchBatchForUser() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->never() )->method( 'addWatchBatchForUser' );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $this->setExpectedException( DBReadOnlyError::class );
+ $noWriteService->addWatchBatchForUser( new UserIdentityValue( 1, 'MockUser', 0 ), [] );
+ }
+
+ public function testRemoveWatch() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->never() )->method( 'removeWatch' );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $this->setExpectedException( DBReadOnlyError::class );
+ $noWriteService->removeWatch(
+ new UserIdentityValue( 1, 'MockUser', 0 ), new TitleValue( 0, 'Foo' ) );
+ }
+
+ public function testSetNotificationTimestampsForUser() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->never() )->method( 'setNotificationTimestampsForUser' );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $this->setExpectedException( DBReadOnlyError::class );
+ $noWriteService->setNotificationTimestampsForUser(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ 'timestamp',
+ []
+ );
+ }
+
+ public function testUpdateNotificationTimestamp() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->never() )->method( 'updateNotificationTimestamp' );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $this->setExpectedException( DBReadOnlyError::class );
+ $noWriteService->updateNotificationTimestamp(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ new TitleValue( 0, 'Foo' ),
+ 'timestamp'
+ );
+ }
+
+ public function testResetNotificationTimestamp() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->never() )->method( 'resetNotificationTimestamp' );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $this->setExpectedException( DBReadOnlyError::class );
+ $noWriteService->resetNotificationTimestamp(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ new TitleValue( 0, 'Foo' )
+ );
+ }
+
+ public function testCountWatchedItems() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )->method( 'countWatchedItems' )->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->countWatchedItems(
+ new UserIdentityValue( 1, 'MockUser', 0 )
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testCountWatchers() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )->method( 'countWatchers' )->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->countWatchers(
+ new TitleValue( 0, 'Foo' )
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testCountVisitingWatchers() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )
+ ->method( 'countVisitingWatchers' )
+ ->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->countVisitingWatchers(
+ new TitleValue( 0, 'Foo' ),
+ 9
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testCountWatchersMultiple() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )
+ ->method( 'countVisitingWatchersMultiple' )
+ ->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->countWatchersMultiple(
+ [ new TitleValue( 0, 'Foo' ) ],
+ []
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testCountVisitingWatchersMultiple() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )
+ ->method( 'countVisitingWatchersMultiple' )
+ ->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->countVisitingWatchersMultiple(
+ [ [ new TitleValue( 0, 'Foo' ), 99 ] ],
+ 11
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testGetWatchedItem() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )->method( 'getWatchedItem' )->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->getWatchedItem(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ new TitleValue( 0, 'Foo' )
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testLoadWatchedItem() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )->method( 'loadWatchedItem' )->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->loadWatchedItem(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ new TitleValue( 0, 'Foo' )
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testGetWatchedItemsForUser() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )
+ ->method( 'getWatchedItemsForUser' )
+ ->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->getWatchedItemsForUser(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ []
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testIsWatched() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )->method( 'isWatched' )->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->isWatched(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ new TitleValue( 0, 'Foo' )
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testGetNotificationTimestampsBatch() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )
+ ->method( 'getNotificationTimestampsBatch' )
+ ->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->getNotificationTimestampsBatch(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ [ new TitleValue( 0, 'Foo' ) ]
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testCountUnreadNotifications() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $innerService->expects( $this->once() )
+ ->method( 'countUnreadNotifications' )
+ ->willReturn( __METHOD__ );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $return = $noWriteService->countUnreadNotifications(
+ new UserIdentityValue( 1, 'MockUser', 0 ),
+ 88
+ );
+ $this->assertEquals( __METHOD__, $return );
+ }
+
+ public function testDuplicateAllAssociatedEntries() {
+ /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+ $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+ $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+ $this->setExpectedException( DBReadOnlyError::class );
+ $noWriteService->duplicateAllAssociatedEntries(
+ new TitleValue( 0, 'Foo' ),
+ new TitleValue( 0, 'Bar' )
+ );
+ }
+
+}