wiki.techinc.nl/tests/phpunit/unit/includes/skins/SkinFactoryTest.php

161 lines
4.9 KiB
PHP
Raw Normal View History

<?php
use Psr\Container\ContainerInterface;
use Wikimedia\ObjectFactory\ObjectFactory;
/**
* @covers SkinFactory
*/
class SkinFactoryTest extends \MediaWikiUnitTestCase {
private function createSkinFactory( $service = null, $options = [] ): SkinFactory {
$objectFactory = $service
? new ObjectFactory( $service )
: new ObjectFactory( $this->createMock( ContainerInterface::class ) );
return new SkinFactory( $objectFactory, $options );
}
public function testRegisterWithInvalidCallable() {
$factory = $this->createSkinFactory();
$this->expectException( InvalidArgumentException::class );
$factory->register( 'invalid', 'Invalid', 'Invalid callback' );
}
public function testRegisterWithCallable() {
$factory = $this->createSkinFactory();
$instance = new SkinFallback();
$factory->register( 'fallback', 'Fallback', static function () use ( $instance ) {
return $instance;
}, true );
$this->assertSame( $instance, $factory->makeSkin( 'fallback' ) );
}
public function testRegisterWithSpec() {
$factory = $this->createSkinFactory();
$factory->register( 'fallback', 'Fallback', [
'class' => SkinFallback::class
], true );
$this->assertInstanceOf( SkinFallback::class, $factory->makeSkin( 'fallback' ) );
}
public function testMakeSkinWithNoBuilders() {
$factory = $this->createSkinFactory();
$this->expectException( SkinException::class );
$factory->makeSkin( 'nobuilderregistered' );
}
public function testMakeSkinWithInvalidCallback() {
$factory = $this->createSkinFactory();
$factory->register( 'unittest', 'Unittest', static function () {
// Not a Skin object
return true;
} );
$this->expectException( UnexpectedValueException::class );
$factory->makeSkin( 'unittest' );
}
public function testMakeSkinWithValidCallback() {
$factory = $this->createSkinFactory();
$factory->register( 'testfallback', 'TestFallback', static function () {
return new SkinFallback();
} );
$skin = $factory->makeSkin( 'testfallback' );
$this->assertInstanceOf( SkinFallback::class, $skin );
Skin: Make skins aware of their registered skin name Remove the need for skin classes to have a hardcoded string as skinname property value. This previously created the possibility for the value to not match the skinname in the SkinFactory registry, which creates confusing situations where message keys and load.php urls are crafted with the internal skinname, but all other handling (useskin, preferences, hooks, SkinFactory, ResourceLoader, etc.) operate on the names in the registry. We could enforce the matching by requiring a 1:1 relationship between skinnames and Skin sub classes, but that is not backwards-compatible with the 1:many map that wgValidSkinNames provides, and not compatible SkinFactory either, which supports a factory function to return an object. This makes a lot of sense and allows Skin-classees to be re-used and composed with injection. If we do want to enforce 1:1, we could validate it with a structure PHPUnit test, but instead this change just uses the injected name from the constructor (passed by ServiceWiring, previously unused). The added unit test shows the new behaviour. Before this change, getSkinName() on SkinFallback would always return 'fallback', whereas now each instance of the class adheres to the registered name (if it differs from the default). Update the two direct uses of protected $skin->skinname to use $skin->getSkinName() instead to enable sub-classes to optionally implement an alternate source for the self-name (or to hardcode it there as before). Bug: T173546 Change-Id: I4383dcc3094da6e3c9ac12dc6c9311128db9db6e
2017-08-25 21:25:57 +00:00
$this->assertEquals( 'fallback', $skin->getSkinName() );
}
public function testMakeSkinWithValidSpec() {
$serviceInstance = (object)[];
$serviceContainer = $this->createMock( ContainerInterface::class );
$serviceContainer->method( 'has' )->willReturn( true );
$serviceContainer->method( 'get' )->willReturn( $serviceInstance );
$args = [];
$factory = $this->createSkinFactory( $serviceContainer );
$factory->register( 'testfallback', 'TestFallback', [
'factory' => static function ( $service, $options ) use ( &$args ) {
$args = [ $service, $options ];
return new SkinFallback();
},
'services' => [
'testservice'
]
] );
$skin = $factory->makeSkin( 'testfallback' );
$this->assertInstanceOf( SkinFallback::class, $skin );
$this->assertEquals( 'fallback', $skin->getSkinName() );
$this->assertSame( 'testfallback', $args[1]['name'] );
$this->assertSame( $serviceInstance, $args[0] );
}
public function testRegisterReplaces() {
$factory = $this->createSkinFactory();
$s1 = $this->createMock( Skin::class );
$factory->register( 'foo', 'Skin 1',
static function () use ( $s1 ) {
return $s1;
},
true
);
$this->assertEquals( [ 'foo' => 'Skin 1' ], $factory->getSkinNames() );
$this->assertSame( $s1, $factory->makeSkin( 'foo' ) );
$this->assertSame( [], $factory->getAllowedSkins(), 'skipped' );
// Skippable state from previous register() call must not leak to replacement
$s2 = $this->createMock( Skin::class );
$factory->register( 'foo', 'Skin 2',
static function () use ( $s2 ) {
return $s2;
}
);
$this->assertEquals( [ 'foo' => 'Skin 2' ], $factory->getSkinNames() );
$this->assertSame( $s2, $factory->makeSkin( 'foo' ) );
$this->assertSame( [ 'foo' => 'Skin 2' ], $factory->getAllowedSkins(), 'not skipped' );
}
public function testGetSkinNames() {
$factory = $this->createSkinFactory();
$factory->register( 'skin1', 'Skin1', [] );
$factory->register( 'skin2', 'Skin2', [] );
$names = $factory->getSkinNames();
$this->assertEquals( 'Skin1', $names['skin1'] );
$this->assertEquals( 'Skin2', $names['skin2'] );
}
public function testGetAllowedSkins() {
$sf = $this->createSkinFactory( null, [ 'quux' ] );
$sf->register( 'foo', 'Foo', [] );
$sf->register( 'apioutput', 'ApiOutput', [], true );
// Skippable state is unspecified here and must inherit from site config,
// which we seeded with 'quux', and thus skipped from allowed skins.
$sf->register( 'quux', 'Quux', [] );
$sf->register( 'fallback', 'Fallback', [], true );
$sf->register( 'bar', 'Barbar', [] );
$this->assertEquals(
[ 'foo' => 'Foo', 'bar' => 'Barbar' ],
$sf->getAllowedSkins()
);
}
public function testGetAllowedSkinsEmpty() {
$sf = $this->createSkinFactory();
$sf->register( 'apioutput', 'ApiOutput', [], true );
$sf->register( 'fallback', 'Fallback', [], true );
$this->assertEquals( [], $sf->getAllowedSkins() );
}
}