'MediaWikiPHPUnitResultPrinter' => "$testDir/phpunit/MediaWikiPHPUnitResultPrinter.php",
'MediaWikiPHPUnitTestListener' => "$testDir/phpunit/MediaWikiPHPUnitTestListener.php",
'MediaWikiTestCase' => "$testDir/phpunit/MediaWikiTestCase.php",
+ 'MediaWikiUnitTestCase' => "$testDir/phpunit/MediaWikiUnitTestCase.php",
'MediaWikiTestResult' => "$testDir/phpunit/MediaWikiTestResult.php",
'MediaWikiTestRunner' => "$testDir/phpunit/MediaWikiTestRunner.php",
'PHPUnit4And6Compat' => "$testDir/phpunit/PHPUnit4And6Compat.php",
--- /dev/null
+<?php
+/**
+ * Base class for MediaWiki unit tests.
+ *
+ * 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
+ */
+
+use PHPUnit\Framework\TestCase;
+
+abstract class MediaWikiUnitTestCase extends TestCase {
+ use PHPUnit4And6Compat;
+ use MediaWikiCoversValidator;
+}
+++ /dev/null
-<?php
-
-/**
- * @covers PasswordFactory
- */
-class PasswordFactoryTest extends MediaWikiTestCase {
- public function testConstruct() {
- $pf = new PasswordFactory();
- $this->assertEquals( [ '' ], array_keys( $pf->getTypes() ) );
- $this->assertEquals( '', $pf->getDefaultType() );
-
- $pf = new PasswordFactory( [
- 'foo' => [ 'class' => 'FooPassword' ],
- 'bar' => [ 'class' => 'BarPassword', 'baz' => 'boom' ],
- ], 'foo' );
- $this->assertEquals( [ '', 'foo', 'bar' ], array_keys( $pf->getTypes() ) );
- $this->assertArraySubset( [ 'class' => 'BarPassword', 'baz' => 'boom' ], $pf->getTypes()['bar'] );
- $this->assertEquals( 'foo', $pf->getDefaultType() );
- }
-
- public function testRegister() {
- $pf = new PasswordFactory;
- $pf->register( 'foo', [ 'class' => InvalidPassword::class ] );
- $this->assertArrayHasKey( 'foo', $pf->getTypes() );
- }
-
- public function testSetDefaultType() {
- $pf = new PasswordFactory;
- $pf->register( '1', [ 'class' => InvalidPassword::class ] );
- $pf->register( '2', [ 'class' => InvalidPassword::class ] );
- $pf->setDefaultType( '1' );
- $this->assertSame( '1', $pf->getDefaultType() );
- $pf->setDefaultType( '2' );
- $this->assertSame( '2', $pf->getDefaultType() );
- }
-
- /**
- * @expectedException Exception
- */
- public function testSetDefaultTypeError() {
- $pf = new PasswordFactory;
- $pf->setDefaultType( 'bogus' );
- }
-
- public function testInit() {
- $config = new HashConfig( [
- 'PasswordConfig' => [
- 'foo' => [ 'class' => InvalidPassword::class ],
- ],
- 'PasswordDefault' => 'foo'
- ] );
- $pf = new PasswordFactory;
- $pf->init( $config );
- $this->assertSame( 'foo', $pf->getDefaultType() );
- $this->assertArrayHasKey( 'foo', $pf->getTypes() );
- }
-
- public function testNewFromCiphertext() {
- $pf = new PasswordFactory;
- $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
- $pw = $pf->newFromCiphertext( ':B:salt:d529e941509eb9e9b9cfaeae1fe7ca23' );
- $this->assertInstanceOf( MWSaltedPassword::class, $pw );
- }
-
- public function provideNewFromCiphertextErrors() {
- return [ [ 'blah' ], [ ':blah:' ] ];
- }
-
- /**
- * @dataProvider provideNewFromCiphertextErrors
- * @expectedException PasswordError
- */
- public function testNewFromCiphertextErrors( $hash ) {
- $pf = new PasswordFactory;
- $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
- $pf->newFromCiphertext( $hash );
- }
-
- public function testNewFromType() {
- $pf = new PasswordFactory;
- $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
- $pw = $pf->newFromType( 'B' );
- $this->assertInstanceOf( MWSaltedPassword::class, $pw );
- }
-
- /**
- * @expectedException PasswordError
- */
- public function testNewFromTypeError() {
- $pf = new PasswordFactory;
- $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
- $pf->newFromType( 'bogus' );
- }
-
- public function testNewFromPlaintext() {
- $pf = new PasswordFactory;
- $pf->register( 'A', [ 'class' => MWOldPassword::class ] );
- $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
- $pf->setDefaultType( 'A' );
-
- $this->assertInstanceOf( InvalidPassword::class, $pf->newFromPlaintext( null ) );
- $this->assertInstanceOf( MWOldPassword::class, $pf->newFromPlaintext( 'password' ) );
- $this->assertInstanceOf( MWSaltedPassword::class,
- $pf->newFromPlaintext( 'password', $pf->newFromType( 'B' ) ) );
- }
-
- public function testNeedsUpdate() {
- $pf = new PasswordFactory;
- $pf->register( 'A', [ 'class' => MWOldPassword::class ] );
- $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
- $pf->setDefaultType( 'A' );
-
- $this->assertFalse( $pf->needsUpdate( $pf->newFromType( 'A' ) ) );
- $this->assertTrue( $pf->needsUpdate( $pf->newFromType( 'B' ) ) );
- }
-
- public function testGenerateRandomPasswordString() {
- $this->assertSame( 13, strlen( PasswordFactory::generateRandomPasswordString( 13 ) ) );
- }
-
- public function testNewInvalidPassword() {
- $this->assertInstanceOf( InvalidPassword::class, PasswordFactory::newInvalidPassword() );
- }
-}
<testsuite name="documentation">
<directory>documentation</directory>
</testsuite>
+ <testsuite name="unit">
+ <directory>unit</directory>
+ </testsuite>
</testsuites>
<groups>
<exclude>
- <group>Utility</group>
<group>Broken</group>
- <group>Stub</group>
</exclude>
</groups>
<filter>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit bootstrap="unit/initUnitTests.php"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
+
+ colors="true"
+ backupGlobals="false"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ forceCoversAnnotation="true"
+ stopOnFailure="false"
+ timeoutForSmallTests="10"
+ timeoutForMediumTests="30"
+ timeoutForLargeTests="60"
+ beStrictAboutTestsThatDoNotTestAnything="true"
+ beStrictAboutOutputDuringTests="true"
+ beStrictAboutTestSize="true"
+ verbose="false">
+ <testsuites>
+ <testsuite name="tests">
+ <directory>unit</directory>
+ </testsuite>
+ </testsuites>
+ <groups>
+ <exclude>
+ <group>Broken</group>
+ </exclude>
+ </groups>
+ <filter>
+ <whitelist addUncoveredFilesFromWhitelist="true">
+ <directory suffix=".php">../../includes</directory>
+ <directory suffix=".php">../../languages</directory>
+ <directory suffix=".php">../../maintenance</directory>
+ <exclude>
+ <directory suffix=".php">../../languages/messages</directory>
+ <file>../../languages/data/normalize-ar.php</file>
+ <file>../../languages/data/normalize-ml.php</file>
+ </exclude>
+ </whitelist>
+ </filter>
+</phpunit>
--- /dev/null
+<?php
+
+/**
+ * @covers PasswordFactory
+ */
+class PasswordFactoryTest extends MediaWikiUnitTestCase {
+ public function testConstruct() {
+ $pf = new PasswordFactory();
+ $this->assertEquals( [ '' ], array_keys( $pf->getTypes() ) );
+ $this->assertEquals( '', $pf->getDefaultType() );
+
+ $pf = new PasswordFactory( [
+ 'foo' => [ 'class' => 'FooPassword' ],
+ 'bar' => [ 'class' => 'BarPassword', 'baz' => 'boom' ],
+ ], 'foo' );
+ $this->assertEquals( [ '', 'foo', 'bar' ], array_keys( $pf->getTypes() ) );
+ $this->assertArraySubset( [ 'class' => 'BarPassword', 'baz' => 'boom' ], $pf->getTypes()['bar'] );
+ $this->assertEquals( 'foo', $pf->getDefaultType() );
+ }
+
+ public function testRegister() {
+ $pf = new PasswordFactory;
+ $pf->register( 'foo', [ 'class' => InvalidPassword::class ] );
+ $this->assertArrayHasKey( 'foo', $pf->getTypes() );
+ }
+
+ public function testSetDefaultType() {
+ $pf = new PasswordFactory;
+ $pf->register( '1', [ 'class' => InvalidPassword::class ] );
+ $pf->register( '2', [ 'class' => InvalidPassword::class ] );
+ $pf->setDefaultType( '1' );
+ $this->assertSame( '1', $pf->getDefaultType() );
+ $pf->setDefaultType( '2' );
+ $this->assertSame( '2', $pf->getDefaultType() );
+ }
+
+ /**
+ * @expectedException Exception
+ */
+ public function testSetDefaultTypeError() {
+ $pf = new PasswordFactory;
+ $pf->setDefaultType( 'bogus' );
+ }
+
+ public function testInit() {
+ $config = new HashConfig( [
+ 'PasswordConfig' => [
+ 'foo' => [ 'class' => InvalidPassword::class ],
+ ],
+ 'PasswordDefault' => 'foo'
+ ] );
+ $pf = new PasswordFactory;
+ $pf->init( $config );
+ $this->assertSame( 'foo', $pf->getDefaultType() );
+ $this->assertArrayHasKey( 'foo', $pf->getTypes() );
+ }
+
+ public function testNewFromCiphertext() {
+ $pf = new PasswordFactory;
+ $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
+ $pw = $pf->newFromCiphertext( ':B:salt:d529e941509eb9e9b9cfaeae1fe7ca23' );
+ $this->assertInstanceOf( MWSaltedPassword::class, $pw );
+ }
+
+ public function provideNewFromCiphertextErrors() {
+ return [ [ 'blah' ], [ ':blah:' ] ];
+ }
+
+ /**
+ * @dataProvider provideNewFromCiphertextErrors
+ * @expectedException PasswordError
+ */
+ public function testNewFromCiphertextErrors( $hash ) {
+ $pf = new PasswordFactory;
+ $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
+ $pf->newFromCiphertext( $hash );
+ }
+
+ public function testNewFromType() {
+ $pf = new PasswordFactory;
+ $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
+ $pw = $pf->newFromType( 'B' );
+ $this->assertInstanceOf( MWSaltedPassword::class, $pw );
+ }
+
+ /**
+ * @expectedException PasswordError
+ */
+ public function testNewFromTypeError() {
+ $pf = new PasswordFactory;
+ $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
+ $pf->newFromType( 'bogus' );
+ }
+
+ public function testNewFromPlaintext() {
+ $pf = new PasswordFactory;
+ $pf->register( 'A', [ 'class' => MWOldPassword::class ] );
+ $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
+ $pf->setDefaultType( 'A' );
+
+ $this->assertInstanceOf( InvalidPassword::class, $pf->newFromPlaintext( null ) );
+ $this->assertInstanceOf( MWOldPassword::class, $pf->newFromPlaintext( 'password' ) );
+ $this->assertInstanceOf( MWSaltedPassword::class,
+ $pf->newFromPlaintext( 'password', $pf->newFromType( 'B' ) ) );
+ }
+
+ public function testNeedsUpdate() {
+ $pf = new PasswordFactory;
+ $pf->register( 'A', [ 'class' => MWOldPassword::class ] );
+ $pf->register( 'B', [ 'class' => MWSaltedPassword::class ] );
+ $pf->setDefaultType( 'A' );
+
+ $this->assertFalse( $pf->needsUpdate( $pf->newFromType( 'A' ) ) );
+ $this->assertTrue( $pf->needsUpdate( $pf->newFromType( 'B' ) ) );
+ }
+
+ public function testGenerateRandomPasswordString() {
+ $this->assertSame( 13, strlen( PasswordFactory::generateRandomPasswordString( 13 ) ) );
+ }
+
+ public function testNewInvalidPassword() {
+ $this->assertInstanceOf( InvalidPassword::class, PasswordFactory::newInvalidPassword() );
+ }
+}
--- /dev/null
+<?php
+/**
+ * PHPUnit bootstrap file for the unit test suite.
+ *
+ * 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
+ */
+
+if ( PHP_SAPI !== 'cli' ) {
+ die( 'This file is only meant to be executed indirectly by PHPUnit\'s bootstrap process!' );
+}
+
+/**
+ * PHPUnit includes the bootstrap file inside a method body, while most MediaWiki startup files
+ * assume to be included in the global scope.
+ * This utility provides a way to include these files: it makes all globals available in the
+ * inclusion scope before including the file, then exports all new or changed globals.
+ *
+ * @param string $fileName the file to include
+ */
+function wfRequireOnceInGlobalScope( $fileName ) {
+ // phpcs:disable MediaWiki.Usage.ForbiddenFunctions.extract
+ extract( $GLOBALS, EXTR_REFS | EXTR_SKIP );
+ // phpcs:enable
+
+ require_once $fileName;
+
+ foreach ( get_defined_vars() as $varName => $value ) {
+ $GLOBALS[$varName] = $value;
+ }
+}
+
+define( 'MEDIAWIKI', true );
+define( 'MW_PHPUNIT_TEST', true );
+
+// We don't use a settings file here but some code still assumes that one exists
+define( 'MW_CONFIG_FILE', 'LocalSettings.php' );
+
+$IP = realpath( __DIR__ . '/../../..' );
+
+// these variables must be defined before setup runs
+$GLOBALS['IP'] = $IP;
+$GLOBALS['wgCommandLineMode'] = true;
+
+require_once "$IP/tests/common/TestSetup.php";
+
+wfRequireOnceInGlobalScope( "$IP/includes/AutoLoader.php" );
+wfRequireOnceInGlobalScope( "$IP/includes/Defines.php" );
+wfRequireOnceInGlobalScope( "$IP/includes/DefaultSettings.php" );
+wfRequireOnceInGlobalScope( "$IP/includes/GlobalFunctions.php" );
+
+require_once "$IP/tests/common/TestsAutoLoader.php";
+
+TestSetup::applyInitialConfig();