wiki.techinc.nl/tests/phpunit/unit/includes/content/ContentHandlerFactoryTest.php
James D. Forrester f7ce0a0976 Move remaining four classes in includes/content into Content namespace
Bug: T353458
Change-Id: Ia0f3e22078550be410c4b87faf6aa4eabe6e270d
2024-08-10 10:40:53 +02:00

402 lines
11 KiB
PHP

<?php
namespace MediaWiki\Tests\Unit\Content;
use DummyContentHandlerForTesting;
use Error;
use InvalidArgumentException;
use MediaWiki\Content\ContentHandler;
use MediaWiki\Content\ContentHandlerFactory;
use MediaWiki\HookContainer\HookContainer;
use MediaWikiUnitTestCase;
use MWUnknownContentModelException;
use Psr\Log\LogLevel;
use TestLogger;
use UnexpectedValueException;
use Wikimedia\ObjectFactory\ObjectFactory;
/**
* @group ContentHandlerFactory
* @covers \MediaWiki\Content\ContentHandlerFactory
*/
class ContentHandlerFactoryTest extends MediaWikiUnitTestCase {
private TestLogger $logger;
protected function setUp(): void {
parent::setUp();
$this->logger = new TestLogger( false, static function ( $message, $level ) {
return $level === LogLevel::INFO ? null : $message;
} );
}
public static function provideHandlerSpecs() {
return [
'typical list' => [
[
'ExistClassName' => DummyContentHandlerForTesting::class,
'ExistCallbackWithExistClassName' => static function ( $modelID ) {
return new DummyContentHandlerForTesting( $modelID );
},
],
DummyContentHandlerForTesting::class,
],
];
}
/**
* @dataProvider provideHandlerSpecs $handlerSpecs
*/
public function testGetContentHandler_callWithProvider_same(
array $handlerSpecs, string $contentHandlerClass
): void {
$contentHandlerExpected = new $contentHandlerClass( 'dummy' );
$objectFactory = $this->createMock( ObjectFactory::class );
$hookContainer = $this->createMock( HookContainer::class );
$factory = new ContentHandlerFactory(
$handlerSpecs,
$objectFactory,
$hookContainer,
$this->logger
);
$returnMap = [];
foreach ( $handlerSpecs as $modelID => $handlerSpec ) {
$returnMap[] = [
$handlerSpec,
[
'assertClass' => ContentHandler::class,
'allowCallable' => true,
'allowClassName' => true,
'extraArgs' => [ $modelID ],
],
$contentHandlerExpected
];
}
$objectFactory
->method( 'createObject' )
->willReturnMap( $returnMap );
foreach ( $handlerSpecs as $modelID => $handlerSpec ) {
$this->assertSame( $contentHandlerExpected, $factory->getContentHandler( $modelID ) );
}
}
/**
* @dataProvider provideHandlerSpecs $handlerSpecs
*/
public function testGetContentHandler_hookWithProvider_same(
array $handlerSpecs,
string $contentHandlerClass
): void {
$contentHandlerExpected = new $contentHandlerClass( 'dummy' );
$hookContainer = $this->createHookContainer();
$factory = new ContentHandlerFactory(
[],
$this->createMock( ObjectFactory::class ),
$hookContainer,
$this->logger
);
foreach ( $handlerSpecs as $modelID => $handlerSpec ) {
$this->assertFalse( $factory->isDefinedModel( $modelID ) );
$contentHandler = null;
$hookContainer->register( 'ContentHandlerForModelID',
static function ( $handlerSpec, &$contentHandler ) use (
$contentHandlerExpected
) {
$contentHandler = $contentHandlerExpected;
return true;
} );
$contentHandler = $factory->getContentHandler( $modelID );
$this->assertSame( $contentHandlerExpected, $contentHandler, $modelID );
$this->assertTrue( $factory->isDefinedModel( $modelID ), $modelID );
}
}
public static function provideHandlerSpecsWithException(): array {
return [
'Callback exists but returns the wrong type' => [
[
'ExistCallbackWithWrongType' => static function () {
return true;
}
],
UnexpectedValueException::class
],
'Callback exists but returns null' => [
[
'ExistCallbackWithNull' => static function () {
return null;
}
],
UnexpectedValueException::class
],
'Callback exists but returns the empty string' => [
[
'ExistCallbackWithEmptyString' => static function () {
return '';
}
],
UnexpectedValueException::class
],
'Wrong class name' => [
[
'WrongClassName' => self::class
],
UnexpectedValueException::class
],
'Wrong type' => [
[
'WrongType' => true
],
InvalidArgumentException::class
],
'Is null' => [
[
'NullType' => null
],
MWUnknownContentModelException::class
],
'Class does not exist' => [
[
'WrongClassNameNotExist' => 'ClassNameNotExist'
],
InvalidArgumentException::class
],
'Callback with non-existing class name' => [
[
'ExistCallbackWithNotExistClassName' => static function () {
return ClassNameNotExist();
},
],
Error::class
],
'Empty string' => [
[
'EmptyString' => '',
],
InvalidArgumentException::class
],
];
}
/**
* @dataProvider provideHandlerSpecsWithException
*/
public function testCreateContentHandlerForModelID_callWithProvider_throwsException(
array $handlerSpecs,
string $exceptionClassName
): void {
if ( count( $handlerSpecs ) !== 1 ) {
$this->fail( 'Dataprovider provided wrong amount of specs' );
}
$factory = new ContentHandlerFactory(
$handlerSpecs,
$this->createSimpleObjectFactory(),
$this->createMock( HookContainer::class ),
$this->logger
);
$modelID = key( $handlerSpecs );
$this->expectException( $exceptionClassName );
$factory->getContentHandler( $modelID );
}
public function testCreateContentHandlerForModelID_callNotExist_throwMWUCMException() {
$this->expectException( MWUnknownContentModelException::class );
$factory = new ContentHandlerFactory(
[],
$this->createMock( ObjectFactory::class ),
$this->createMock( HookContainer::class ),
$this->logger
);
$factory->getContentHandler( 'ModelNameNotExist' );
}
public function testDefineContentHandler_flow_throwsException() {
$objectFactory = $this->createMock( ObjectFactory::class );
$objectFactory
->method( 'createObject' )
->willReturn( $this->createMock( DummyContentHandlerForTesting::class ) );
$factory = new ContentHandlerFactory(
[],
$objectFactory,
$this->createMock( HookContainer::class ),
$this->logger
);
$this->assertFalse( $factory->isDefinedModel( 'define test' ) );
$factory->defineContentHandler( 'define test', DummyContentHandlerForTesting::class );
$this->assertTrue( $factory->isDefinedModel( 'define test' ) );
$this->assertInstanceOf(
DummyContentHandlerForTesting::class,
$factory->getContentHandler( 'define test' )
);
}
/**
* @dataProvider provideValidDummySpecList
*/
public function testGetContentModels_flow_same(
string $name1, string $name2, string $name3, string $name4
): void {
$hookContainer = $this->createHookContainer();
$factory = new ContentHandlerFactory(
[
$name1 => DummyContentHandlerForTesting::class,
$name2 => DummyContentHandlerForTesting::class,
],
$this->createMock( ObjectFactory::class ),
$hookContainer,
$this->logger
);
$this->assertArrayEquals(
[ $name1, $name2, ],
$factory->getContentModels() );
$factory->defineContentHandler(
$name3,
static function () {
}
);
$this->assertArrayEquals(
[ $name1, $name2, $name3, ],
$factory->getContentModels()
);
$hookContainer->register( 'GetContentModels',
static function ( &$models ) use ( $name4 ) {
$models[] = $name4;
} );
$this->assertArrayEquals(
[ $name1, $name2, $name3, $name4, ],
$factory->getContentModels()
);
}
/**
* @dataProvider provideValidDummySpecList
*/
public function testIsDefinedModel_flow_same(
string $name1, string $name2, string $name3, string $name4
): void {
$hookContainer = $this->createHookContainer();
$factory = new ContentHandlerFactory(
[
$name1 => DummyContentHandlerForTesting::class,
$name2 => DummyContentHandlerForTesting::class,
],
$this->createMock( ObjectFactory::class ),
$hookContainer,
$this->logger
);
$this->assertTrue( $factory->isDefinedModel( $name1 ) );
$this->assertTrue( $factory->isDefinedModel( $name2 ) );
$this->assertFalse( $factory->isDefinedModel( $name3 ) );
$this->assertFalse( $factory->isDefinedModel( $name4 ) );
$this->assertFalse( $factory->isDefinedModel( 'not exist name' ) );
$factory->defineContentHandler(
$name3,
static function () {
}
);
$this->assertTrue( $factory->isDefinedModel( $name1 ) );
$this->assertTrue( $factory->isDefinedModel( $name2 ) );
$this->assertTrue( $factory->isDefinedModel( $name3 ) );
$this->assertFalse( $factory->isDefinedModel( $name4 ) );
$this->assertFalse( $factory->isDefinedModel( 'not exist name' ) );
$hookContainer->register(
'GetContentModels',
static function ( &$models ) use ( $name4 ) {
$models[] = $name4;
} );
$this->assertTrue( $factory->isDefinedModel( $name1 ) );
$this->assertTrue( $factory->isDefinedModel( $name2 ) );
$this->assertTrue( $factory->isDefinedModel( $name3 ) );
$this->assertTrue( $factory->isDefinedModel( $name4 ) );
$this->assertFalse( $factory->isDefinedModel( 'not exist name' ) );
}
public static function provideValidDummySpecList() {
return [
'1-0-3' => [
'mock name 1',
'mock name 0',
'mock name 3',
'mock name 4',
],
];
}
public function testGetContentModels_empty_empty() {
$factory = new ContentHandlerFactory(
[],
$this->createMock( ObjectFactory::class ),
$this->createMock( HookContainer::class ),
$this->logger
);
$this->assertArrayEquals( [], $factory->getContentModels() );
}
public function testGetAllContentFormats_flow_same() {
$contentHandler1 = $this->createMock( DummyContentHandlerForTesting::class );
$contentHandler1->method( 'getSupportedFormats' )->willReturn( [ 'format 1' ] );
$contentHandler2 = $this->createMock( DummyContentHandlerForTesting::class );
$contentHandler2->method( 'getSupportedFormats' )->willReturn( [ 'format 0' ] );
$contentHandler3 = $this->createMock( DummyContentHandlerForTesting::class );
$contentHandler3->method( 'getSupportedFormats' )->willReturn( [ 'format 3' ] );
$objectFactory = $this->createMock( ObjectFactory::class );
$objectFactory
->method( 'createObject' )
->willReturnOnConsecutiveCalls( $contentHandler1, $contentHandler2, $contentHandler3 );
$factory = new ContentHandlerFactory(
[
'mock name 1' => static function () {
// return new DummyContentHandlerForTesting( 'mock 1', [ 'format 1' ] );
},
'mock name 2' => static function () {
// return new DummyContentHandlerForTesting( 'mock 0', [ 'format 0' ] );
},
],
$objectFactory,
$this->createMock( HookContainer::class ),
$this->logger
);
$this->assertArrayEquals( [
'format 1',
'format 0',
],
$factory->getAllContentFormats() );
$factory->defineContentHandler( 'some new name',
static function () {
// return new DummyContentHandlerForTesting( 'mock defined', [ 'format defined' ] );
} );
$this->assertArrayEquals( [
'format 1',
'format 0',
'format 3',
],
$factory->getAllContentFormats() );
}
}