From: Amir Sarabadani Date: Tue, 2 Jul 2019 17:04:44 +0000 (+0200) Subject: Move trivial unit tests, round II X-Git-Tag: 1.34.0-rc.0~1205^2 X-Git-Url: http://git.cyclocoop.org/?a=commitdiff_plain;h=095f5583cb2d508bf5f26940e547a8fcd356ee55;p=lhc%2Fweb%2Fwiklou.git Move trivial unit tests, round II Change-Id: I18e5a1514d7372b34f7fb460adf506a1ac65001f --- diff --git a/tests/phpunit/includes/MediaWikiVersionFetcherTest.php b/tests/phpunit/includes/MediaWikiVersionFetcherTest.php deleted file mode 100644 index 9803081869..0000000000 --- a/tests/phpunit/includes/MediaWikiVersionFetcherTest.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ -class MediaWikiVersionFetcherTest extends MediaWikiTestCase { - - public function testReturnsResult() { - global $wgVersion; - $versionFetcher = new MediaWikiVersionFetcher(); - $this->assertSame( $wgVersion, $versionFetcher->fetchVersion() ); - } - -} diff --git a/tests/phpunit/includes/Rest/EntryPointTest.php b/tests/phpunit/includes/Rest/EntryPointTest.php deleted file mode 100644 index 4f87a70b4f..0000000000 --- a/tests/phpunit/includes/Rest/EntryPointTest.php +++ /dev/null @@ -1,90 +0,0 @@ -getMockBuilder( WebResponse::class ) - ->setMethods( [ 'header' ] ) - ->getMock(); - } - - public static function mockHandlerHeader() { - return new class extends Handler { - public function execute() { - $response = $this->getResponseFactory()->create(); - $response->setHeader( 'Foo', 'Bar' ); - return $response; - } - }; - } - - public function testHeader() { - $webResponse = $this->createWebResponse(); - $webResponse->expects( $this->any() ) - ->method( 'header' ) - ->withConsecutive( - [ 'HTTP/1.1 200 OK', true, null ], - [ 'Foo: Bar', true, null ] - ); - - $entryPoint = new EntryPoint( - new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/header' ) ] ), - $webResponse, - $this->createRouter() ); - $entryPoint->execute(); - $this->assertTrue( true ); - } - - public static function mockHandlerBodyRewind() { - return new class extends Handler { - public function execute() { - $response = $this->getResponseFactory()->create(); - $stream = new Stream( fopen( 'php://memory', 'w+' ) ); - $stream->write( 'hello' ); - $response->setBody( $stream ); - return $response; - } - }; - } - - /** - * Make sure EntryPoint rewinds a seekable body stream before reading. - */ - public function testBodyRewind() { - $entryPoint = new EntryPoint( - new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/bodyRewind' ) ] ), - $this->createWebResponse(), - $this->createRouter() ); - ob_start(); - $entryPoint->execute(); - $this->assertSame( 'hello', ob_get_clean() ); - } - -} diff --git a/tests/phpunit/includes/Rest/Handler/HelloHandlerTest.php b/tests/phpunit/includes/Rest/Handler/HelloHandlerTest.php deleted file mode 100644 index afbaafb757..0000000000 --- a/tests/phpunit/includes/Rest/Handler/HelloHandlerTest.php +++ /dev/null @@ -1,81 +0,0 @@ - [ - [ - 'method' => 'GET', - 'uri' => self::makeUri( '/user/Tim/hello' ), - ], - [ - 'statusCode' => 200, - 'reasonPhrase' => 'OK', - 'protocolVersion' => '1.1', - 'body' => '{"message":"Hello, Tim!"}', - ], - ], - 'method not allowed' => [ - [ - 'method' => 'POST', - 'uri' => self::makeUri( '/user/Tim/hello' ), - ], - [ - 'statusCode' => 405, - 'reasonPhrase' => 'Method Not Allowed', - 'protocolVersion' => '1.1', - 'body' => '{"httpCode":405,"httpReason":"Method Not Allowed"}', - ], - ], - ]; - } - - private static function makeUri( $path ) { - return new Uri( "http://www.example.com/rest$path" ); - } - - /** @dataProvider provideTestViaRouter */ - public function testViaRouter( $requestInfo, $responseInfo ) { - $router = new Router( - [ __DIR__ . '/../testRoutes.json' ], - [], - '/rest', - new EmptyBagOStuff(), - new ResponseFactory() ); - $request = new RequestData( $requestInfo ); - $response = $router->execute( $request ); - if ( isset( $responseInfo['statusCode'] ) ) { - $this->assertSame( $responseInfo['statusCode'], $response->getStatusCode() ); - } - if ( isset( $responseInfo['reasonPhrase'] ) ) { - $this->assertSame( $responseInfo['reasonPhrase'], $response->getReasonPhrase() ); - } - if ( isset( $responseInfo['protocolVersion'] ) ) { - $this->assertSame( $responseInfo['protocolVersion'], $response->getProtocolVersion() ); - } - if ( isset( $responseInfo['body'] ) ) { - $this->assertSame( $responseInfo['body'], $response->getBody()->getContents() ); - } - $this->assertSame( - [], - array_diff( array_keys( $responseInfo ), [ - 'statusCode', - 'reasonPhrase', - 'protocolVersion', - 'body' - ] ), - '$responseInfo may not contain unknown keys' ); - } -} diff --git a/tests/phpunit/includes/Rest/testRoutes.json b/tests/phpunit/includes/Rest/testRoutes.json deleted file mode 100644 index 7e43bb0c5d..0000000000 --- a/tests/phpunit/includes/Rest/testRoutes.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "path": "/user/{name}/hello", - "class": "MediaWiki\\Rest\\Handler\\HelloHandler" - }, - { - "path": "/mock/EntryPoint/header", - "factory": "MediaWiki\\Tests\\Rest\\EntryPointTest::mockHandlerHeader" - }, - { - "path": "/mock/EntryPoint/bodyRewind", - "factory": "MediaWiki\\Tests\\Rest\\EntryPointTest::mockHandlerBodyRewind" - } -] diff --git a/tests/phpunit/includes/Revision/RevisionStoreFactoryTest.php b/tests/phpunit/includes/Revision/RevisionStoreFactoryTest.php deleted file mode 100644 index 84c815d487..0000000000 --- a/tests/phpunit/includes/Revision/RevisionStoreFactoryTest.php +++ /dev/null @@ -1,194 +0,0 @@ -getMockLoadBalancerFactory(), - $this->getMockBlobStoreFactory(), - $this->getNameTableStoreFactory(), - $this->getMockSlotRoleRegistry(), - $this->getHashWANObjectCache(), - $this->getMockCommentStore(), - ActorMigration::newMigration(), - MIGRATION_OLD, - $this->getMockLoggerSpi(), - true - ); - $this->assertTrue( true ); - } - - public function provideWikiIds() { - yield [ true ]; - yield [ false ]; - yield [ 'somewiki' ]; - yield [ 'somewiki', MIGRATION_OLD , false ]; - yield [ 'somewiki', MIGRATION_NEW , true ]; - } - - /** - * @dataProvider provideWikiIds - * @covers \MediaWiki\Revision\RevisionStoreFactory::getRevisionStore - */ - public function testGetRevisionStore( - $dbDomain, - $mcrMigrationStage = MIGRATION_OLD, - $contentHandlerUseDb = true - ) { - $lbFactory = $this->getMockLoadBalancerFactory(); - $blobStoreFactory = $this->getMockBlobStoreFactory(); - $nameTableStoreFactory = $this->getNameTableStoreFactory(); - $slotRoleRegistry = $this->getMockSlotRoleRegistry(); - $cache = $this->getHashWANObjectCache(); - $commentStore = $this->getMockCommentStore(); - $actorMigration = ActorMigration::newMigration(); - $loggerProvider = $this->getMockLoggerSpi(); - - $factory = new RevisionStoreFactory( - $lbFactory, - $blobStoreFactory, - $nameTableStoreFactory, - $slotRoleRegistry, - $cache, - $commentStore, - $actorMigration, - $mcrMigrationStage, - $loggerProvider, - $contentHandlerUseDb - ); - - $store = $factory->getRevisionStore( $dbDomain ); - $wrapper = TestingAccessWrapper::newFromObject( $store ); - - // ensure the correct object type is returned - $this->assertInstanceOf( RevisionStore::class, $store ); - - // ensure the RevisionStore is for the given wikiId - $this->assertSame( $dbDomain, $wrapper->dbDomain ); - - // ensure all other required services are correctly set - $this->assertSame( $cache, $wrapper->cache ); - $this->assertSame( $commentStore, $wrapper->commentStore ); - $this->assertSame( $mcrMigrationStage, $wrapper->mcrMigrationStage ); - $this->assertSame( $actorMigration, $wrapper->actorMigration ); - $this->assertSame( $contentHandlerUseDb, $store->getContentHandlerUseDB() ); - - $this->assertInstanceOf( ILoadBalancer::class, $wrapper->loadBalancer ); - $this->assertInstanceOf( BlobStore::class, $wrapper->blobStore ); - $this->assertInstanceOf( NameTableStore::class, $wrapper->contentModelStore ); - $this->assertInstanceOf( NameTableStore::class, $wrapper->slotRoleStore ); - $this->assertInstanceOf( LoggerInterface::class, $wrapper->logger ); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject|ILoadBalancer - */ - private function getMockLoadBalancer() { - return $this->getMockBuilder( ILoadBalancer::class ) - ->disableOriginalConstructor()->getMock(); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject|ILBFactory - */ - private function getMockLoadBalancerFactory() { - $mock = $this->getMockBuilder( ILBFactory::class ) - ->disableOriginalConstructor()->getMock(); - - $mock->method( 'getMainLB' ) - ->willReturnCallback( function () { - return $this->getMockLoadBalancer(); - } ); - - return $mock; - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject|SqlBlobStore - */ - private function getMockSqlBlobStore() { - return $this->getMockBuilder( SqlBlobStore::class ) - ->disableOriginalConstructor()->getMock(); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject|BlobStoreFactory - */ - private function getMockBlobStoreFactory() { - $mock = $this->getMockBuilder( BlobStoreFactory::class ) - ->disableOriginalConstructor()->getMock(); - - $mock->method( 'newSqlBlobStore' ) - ->willReturnCallback( function () { - return $this->getMockSqlBlobStore(); - } ); - - return $mock; - } - - /** - * @return SlotRoleRegistry - */ - private function getMockSlotRoleRegistry() { - return $this->createMock( SlotRoleRegistry::class ); - } - - /** - * @return NameTableStoreFactory - */ - private function getNameTableStoreFactory() { - return new NameTableStoreFactory( - $this->getMockLoadBalancerFactory(), - $this->getHashWANObjectCache(), - new NullLogger() ); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject|CommentStore - */ - private function getMockCommentStore() { - return $this->getMockBuilder( CommentStore::class ) - ->disableOriginalConstructor()->getMock(); - } - - private function getHashWANObjectCache() { - return new WANObjectCache( [ 'cache' => new \HashBagOStuff() ] ); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject|LoggerSpi - */ - private function getMockLoggerSpi() { - $mock = $this->getMock( LoggerSpi::class ); - - $mock->method( 'getLogger' ) - ->willReturn( new NullLogger() ); - - return $mock; - } - -} diff --git a/tests/phpunit/includes/config/ConfigFactoryTest.php b/tests/phpunit/includes/config/ConfigFactoryTest.php deleted file mode 100644 index ea747afac1..0000000000 --- a/tests/phpunit/includes/config/ConfigFactoryTest.php +++ /dev/null @@ -1,168 +0,0 @@ -register( 'unittest', 'GlobalVarConfig::newInstance' ); - $this->assertInstanceOf( GlobalVarConfig::class, $factory->makeConfig( 'unittest' ) ); - } - - /** - * @covers ConfigFactory::register - */ - public function testRegisterInvalid() { - $factory = new ConfigFactory(); - $this->setExpectedException( InvalidArgumentException::class ); - $factory->register( 'invalid', 'Invalid callback' ); - } - - /** - * @covers ConfigFactory::register - */ - public function testRegisterInvalidInstance() { - $factory = new ConfigFactory(); - $this->setExpectedException( InvalidArgumentException::class ); - $factory->register( 'invalidInstance', new stdClass ); - } - - /** - * @covers ConfigFactory::register - */ - public function testRegisterInstance() { - $config = GlobalVarConfig::newInstance(); - $factory = new ConfigFactory(); - $factory->register( 'unittest', $config ); - $this->assertSame( $config, $factory->makeConfig( 'unittest' ) ); - } - - /** - * @covers ConfigFactory::register - */ - public function testRegisterAgain() { - $factory = new ConfigFactory(); - $factory->register( 'unittest', 'GlobalVarConfig::newInstance' ); - $config1 = $factory->makeConfig( 'unittest' ); - - $factory->register( 'unittest', 'GlobalVarConfig::newInstance' ); - $config2 = $factory->makeConfig( 'unittest' ); - - $this->assertNotSame( $config1, $config2 ); - } - - /** - * @covers ConfigFactory::salvage - */ - public function testSalvage() { - $oldFactory = new ConfigFactory(); - $oldFactory->register( 'foo', 'GlobalVarConfig::newInstance' ); - $oldFactory->register( 'bar', 'GlobalVarConfig::newInstance' ); - $oldFactory->register( 'quux', 'GlobalVarConfig::newInstance' ); - - // instantiate two of the three defined configurations - $foo = $oldFactory->makeConfig( 'foo' ); - $bar = $oldFactory->makeConfig( 'bar' ); - $quux = $oldFactory->makeConfig( 'quux' ); - - // define new config instance - $newFactory = new ConfigFactory(); - $newFactory->register( 'foo', 'GlobalVarConfig::newInstance' ); - $newFactory->register( 'bar', function () { - return new HashConfig(); - } ); - - // "foo" and "quux" are defined in the old and the new factory. - // The old factory has instances for "foo" and "bar", but not "quux". - $newFactory->salvage( $oldFactory ); - - $newFoo = $newFactory->makeConfig( 'foo' ); - $this->assertSame( $foo, $newFoo, 'existing instance should be salvaged' ); - - $newBar = $newFactory->makeConfig( 'bar' ); - $this->assertNotSame( $bar, $newBar, 'don\'t salvage if callbacks differ' ); - - // the new factory doesn't have quux defined, so the quux instance should not be salvaged - $this->setExpectedException( ConfigException::class ); - $newFactory->makeConfig( 'quux' ); - } - - /** - * @covers ConfigFactory::getConfigNames - */ - public function testGetConfigNames() { - $factory = new ConfigFactory(); - $factory->register( 'foo', 'GlobalVarConfig::newInstance' ); - $factory->register( 'bar', new HashConfig() ); - - $this->assertEquals( [ 'foo', 'bar' ], $factory->getConfigNames() ); - } - - /** - * @covers ConfigFactory::makeConfig - */ - public function testMakeConfigWithCallback() { - $factory = new ConfigFactory(); - $factory->register( 'unittest', 'GlobalVarConfig::newInstance' ); - - $conf = $factory->makeConfig( 'unittest' ); - $this->assertInstanceOf( Config::class, $conf ); - $this->assertSame( $conf, $factory->makeConfig( 'unittest' ) ); - } - - /** - * @covers ConfigFactory::makeConfig - */ - public function testMakeConfigWithObject() { - $factory = new ConfigFactory(); - $conf = new HashConfig(); - $factory->register( 'test', $conf ); - $this->assertSame( $conf, $factory->makeConfig( 'test' ) ); - } - - /** - * @covers ConfigFactory::makeConfig - */ - public function testMakeConfigFallback() { - $factory = new ConfigFactory(); - $factory->register( '*', 'GlobalVarConfig::newInstance' ); - $conf = $factory->makeConfig( 'unittest' ); - $this->assertInstanceOf( Config::class, $conf ); - } - - /** - * @covers ConfigFactory::makeConfig - */ - public function testMakeConfigWithNoBuilders() { - $factory = new ConfigFactory(); - $this->setExpectedException( ConfigException::class ); - $factory->makeConfig( 'nobuilderregistered' ); - } - - /** - * @covers ConfigFactory::makeConfig - */ - public function testMakeConfigWithInvalidCallback() { - $factory = new ConfigFactory(); - $factory->register( 'unittest', function () { - return true; // Not a Config object - } ); - $this->setExpectedException( UnexpectedValueException::class ); - $factory->makeConfig( 'unittest' ); - } - - /** - * @covers ConfigFactory::getDefaultInstance - */ - public function testGetDefaultInstance() { - // NOTE: the global config factory returned here has been overwritten - // for operation in test mode. It may not reflect LocalSettings. - $factory = MediaWikiServices::getInstance()->getConfigFactory(); - $this->assertInstanceOf( Config::class, $factory->makeConfig( 'main' ) ); - } - -} diff --git a/tests/phpunit/includes/media/GIFMetadataExtractorTest.php b/tests/phpunit/includes/media/GIFMetadataExtractorTest.php deleted file mode 100644 index 278b441bbd..0000000000 --- a/tests/phpunit/includes/media/GIFMetadataExtractorTest.php +++ /dev/null @@ -1,110 +0,0 @@ -mediaPath = __DIR__ . '/../../data/media/'; - } - - /** - * Put in a file, and see if the metadata coming out is as expected. - * @param string $filename - * @param array $expected The extracted metadata. - * @dataProvider provideGetMetadata - * @covers GIFMetadataExtractor::getMetadata - */ - public function testGetMetadata( $filename, $expected ) { - $actual = GIFMetadataExtractor::getMetadata( $this->mediaPath . $filename ); - $this->assertEquals( $expected, $actual ); - } - - public static function provideGetMetadata() { - $xmpNugget = << - - - - - The interwebs - - - - Bawolff - - - A file to test GIF - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EOF; - $xmpNugget = str_replace( "\r", '', $xmpNugget ); // Windows compat - - return [ - [ - 'nonanimated.gif', - [ - 'comment' => [ 'GIF test file ⁕ Created with GIMP' ], - 'duration' => 0.1, - 'frameCount' => 1, - 'looped' => false, - 'xmp' => '', - ] - ], - [ - 'animated.gif', - [ - 'comment' => [ 'GIF test file . Created with GIMP' ], - 'duration' => 2.4, - 'frameCount' => 4, - 'looped' => true, - 'xmp' => '', - ] - ], - - [ - 'animated-xmp.gif', - [ - 'xmp' => $xmpNugget, - 'duration' => 2.4, - 'frameCount' => 4, - 'looped' => true, - 'comment' => [ 'GIƒ·test·file' ], - ] - ], - ]; - } -} diff --git a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php deleted file mode 100644 index 6b94d0ae6c..0000000000 --- a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php +++ /dev/null @@ -1,201 +0,0 @@ -assertMetadata( $infile, $expected ); - } - - /** - * @dataProvider provideSvgFilesWithXMLMetadata - */ - public function testGetXMLMetadata( $infile, $expected ) { - $r = new XMLReader(); - $this->assertMetadata( $infile, $expected ); - } - - /** - * @dataProvider provideSvgUnits - */ - public function testScaleSVGUnit( $inUnit, $expected ) { - $this->assertEquals( - $expected, - SVGReader::scaleSVGUnit( $inUnit ), - 'SVG unit conversion and scaling failure' - ); - } - - function assertMetadata( $infile, $expected ) { - try { - $data = SVGMetadataExtractor::getMetadata( $infile ); - $this->assertEquals( $expected, $data, 'SVG metadata extraction test' ); - } catch ( MWException $e ) { - if ( $expected === false ) { - $this->assertTrue( true, 'SVG metadata extracted test (expected failure)' ); - } else { - throw $e; - } - } - } - - public static function provideSvgFiles() { - $base = __DIR__ . '/../../data/media'; - - return [ - [ - "$base/Wikimedia-logo.svg", - [ - 'width' => 1024, - 'height' => 1024, - 'originalWidth' => '1024', - 'originalHeight' => '1024', - 'translations' => [], - ] - ], - [ - "$base/QA_icon.svg", - [ - 'width' => 60, - 'height' => 60, - 'originalWidth' => '60', - 'originalHeight' => '60', - 'translations' => [], - ] - ], - [ - "$base/Gtk-media-play-ltr.svg", - [ - 'width' => 60, - 'height' => 60, - 'originalWidth' => '60.0000000', - 'originalHeight' => '60.0000000', - 'translations' => [], - ] - ], - [ - "$base/Toll_Texas_1.svg", - // This file triggered T33719, needs entity expansion in the xmlns checks - [ - 'width' => 385, - 'height' => 385, - 'originalWidth' => '385', - 'originalHeight' => '385.0004883', - 'translations' => [], - ] - ], - [ - "$base/Tux.svg", - [ - 'width' => 512, - 'height' => 594, - 'originalWidth' => '100%', - 'originalHeight' => '100%', - 'title' => 'Tux', - 'translations' => [], - 'description' => 'For more information see: http://commons.wikimedia.org/wiki/Image:Tux.svg', - ] - ], - [ - "$base/Speech_bubbles.svg", - [ - 'width' => 627, - 'height' => 461, - 'originalWidth' => '17.7cm', - 'originalHeight' => '13cm', - 'translations' => [ - 'de' => SVGReader::LANG_FULL_MATCH, - 'fr' => SVGReader::LANG_FULL_MATCH, - 'nl' => SVGReader::LANG_FULL_MATCH, - 'tlh-ca' => SVGReader::LANG_FULL_MATCH, - 'tlh' => SVGReader::LANG_PREFIX_MATCH - ], - ] - ], - [ - "$base/Soccer_ball_animated.svg", - [ - 'width' => 150, - 'height' => 150, - 'originalWidth' => '150', - 'originalHeight' => '150', - 'animated' => true, - 'translations' => [] - ], - ], - [ - "$base/comma_separated_viewbox.svg", - [ - 'width' => 512, - 'height' => 594, - 'originalWidth' => '100%', - 'originalHeight' => '100%', - 'translations' => [] - ], - ], - ]; - } - - public static function provideSvgFilesWithXMLMetadata() { - $base = __DIR__ . '/../../data/media'; - // phpcs:disable Generic.Files.LineLength - $metadata = ' - - image/svg+xml - - - '; - // phpcs:enable - - $metadata = str_replace( "\r", '', $metadata ); // Windows compat - return [ - [ - "$base/US_states_by_total_state_tax_revenue.svg", - [ - 'height' => 593, - 'metadata' => $metadata, - 'width' => 959, - 'originalWidth' => '958.69', - 'originalHeight' => '592.78998', - 'translations' => [], - ] - ], - ]; - } - - public static function provideSvgUnits() { - return [ - [ '1' , 1 ], - [ '1.1' , 1.1 ], - [ '0.1' , 0.1 ], - [ '.1' , 0.1 ], - [ '1e2' , 100 ], - [ '1E2' , 100 ], - [ '+1' , 1 ], - [ '-1' , -1 ], - [ '-1.1' , -1.1 ], - [ '1e+2' , 100 ], - [ '1e-2' , 0.01 ], - [ '10px' , 10 ], - [ '10pt' , 10 * 1.25 ], - [ '10pc' , 10 * 15 ], - [ '10mm' , 10 * 3.543307 ], - [ '10cm' , 10 * 35.43307 ], - [ '10in' , 10 * 90 ], - [ '10em' , 10 * 16 ], - [ '10ex' , 10 * 12 ], - [ '10%' , 51.2 ], - [ '10 px' , 10 ], - // Invalid values - [ '1e1.1', 10 ], - [ '10bp', 10 ], - [ 'p10', null ], - ]; - } -} diff --git a/tests/phpunit/includes/site/CachingSiteStoreTest.php b/tests/phpunit/includes/site/CachingSiteStoreTest.php deleted file mode 100644 index f04d35ca02..0000000000 --- a/tests/phpunit/includes/site/CachingSiteStoreTest.php +++ /dev/null @@ -1,167 +0,0 @@ - - */ -class CachingSiteStoreTest extends MediaWikiTestCase { - - /** - * @covers CachingSiteStore::getSites - */ - public function testGetSites() { - $testSites = TestSites::getSites(); - - $store = new CachingSiteStore( - $this->getHashSiteStore( $testSites ), - ObjectCache::getLocalClusterInstance() - ); - - $sites = $store->getSites(); - - $this->assertInstanceOf( SiteList::class, $sites ); - - /** - * @var Site $site - */ - foreach ( $sites as $site ) { - $this->assertInstanceOf( Site::class, $site ); - } - - foreach ( $testSites as $site ) { - if ( $site->getGlobalId() !== null ) { - $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) ); - } - } - } - - /** - * @covers CachingSiteStore::saveSites - */ - public function testSaveSites() { - $store = new CachingSiteStore( - new HashSiteStore(), ObjectCache::getLocalClusterInstance() - ); - - $sites = []; - - $site = new Site(); - $site->setGlobalId( 'ertrywuutr' ); - $site->setLanguageCode( 'en' ); - $sites[] = $site; - - $site = new MediaWikiSite(); - $site->setGlobalId( 'sdfhxujgkfpth' ); - $site->setLanguageCode( 'nl' ); - $sites[] = $site; - - $this->assertTrue( $store->saveSites( $sites ) ); - - $site = $store->getSite( 'ertrywuutr' ); - $this->assertInstanceOf( Site::class, $site ); - $this->assertEquals( 'en', $site->getLanguageCode() ); - - $site = $store->getSite( 'sdfhxujgkfpth' ); - $this->assertInstanceOf( Site::class, $site ); - $this->assertEquals( 'nl', $site->getLanguageCode() ); - } - - /** - * @covers CachingSiteStore::reset - */ - public function testReset() { - $dbSiteStore = $this->getMockBuilder( SiteStore::class ) - ->disableOriginalConstructor() - ->getMock(); - - $dbSiteStore->expects( $this->any() ) - ->method( 'getSite' ) - ->will( $this->returnValue( $this->getTestSite() ) ); - - $dbSiteStore->expects( $this->any() ) - ->method( 'getSites' ) - ->will( $this->returnCallback( function () { - $siteList = new SiteList(); - $siteList->setSite( $this->getTestSite() ); - - return $siteList; - } ) ); - - $store = new CachingSiteStore( $dbSiteStore, ObjectCache::getLocalClusterInstance() ); - - // initialize internal cache - $this->assertGreaterThan( 0, $store->getSites()->count(), 'count sites' ); - - $store->getSite( 'enwiki' )->setLanguageCode( 'en-ca' ); - - // sanity check: $store should have the new language code for 'enwiki' - $this->assertEquals( 'en-ca', $store->getSite( 'enwiki' )->getLanguageCode(), 'sanity check' ); - - // purge cache - $store->reset(); - - // the internal cache of $store should be updated, and now pulling - // the site from the 'fallback' DBSiteStore with the original language code. - $this->assertEquals( 'en', $store->getSite( 'enwiki' )->getLanguageCode(), 'reset' ); - } - - public function getTestSite() { - $enwiki = new MediaWikiSite(); - $enwiki->setGlobalId( 'enwiki' ); - $enwiki->setLanguageCode( 'en' ); - - return $enwiki; - } - - /** - * @covers CachingSiteStore::clear - */ - public function testClear() { - $store = new CachingSiteStore( - new HashSiteStore(), ObjectCache::getLocalClusterInstance() - ); - $this->assertTrue( $store->clear() ); - - $site = $store->getSite( 'enwiki' ); - $this->assertNull( $site ); - - $sites = $store->getSites(); - $this->assertEquals( 0, $sites->count() ); - } - - /** - * @param Site[] $sites - * - * @return SiteStore - */ - private function getHashSiteStore( array $sites ) { - $siteStore = new HashSiteStore(); - $siteStore->saveSites( $sites ); - - return $siteStore; - } - -} diff --git a/tests/phpunit/includes/site/HashSiteStoreTest.php b/tests/phpunit/includes/site/HashSiteStoreTest.php deleted file mode 100644 index 6269fd39dc..0000000000 --- a/tests/phpunit/includes/site/HashSiteStoreTest.php +++ /dev/null @@ -1,105 +0,0 @@ - - */ -class HashSiteStoreTest extends MediaWikiTestCase { - - /** - * @covers HashSiteStore::getSites - */ - public function testGetSites() { - $expectedSites = []; - - foreach ( TestSites::getSites() as $testSite ) { - $siteId = $testSite->getGlobalId(); - $expectedSites[$siteId] = $testSite; - } - - $siteStore = new HashSiteStore( $expectedSites ); - - $this->assertEquals( new SiteList( $expectedSites ), $siteStore->getSites() ); - } - - /** - * @covers HashSiteStore::saveSite - * @covers HashSiteStore::getSite - */ - public function testSaveSite() { - $store = new HashSiteStore(); - - $site = new Site(); - $site->setGlobalId( 'dewiki' ); - - $this->assertCount( 0, $store->getSites(), '0 sites in store' ); - - $store->saveSite( $site ); - - $this->assertCount( 1, $store->getSites(), 'Store has 1 sites' ); - $this->assertEquals( $site, $store->getSite( 'dewiki' ), 'Store has dewiki' ); - } - - /** - * @covers HashSiteStore::saveSites - */ - public function testSaveSites() { - $store = new HashSiteStore(); - - $sites = []; - - $site = new Site(); - $site->setGlobalId( 'enwiki' ); - $site->setLanguageCode( 'en' ); - $sites[] = $site; - - $site = new MediaWikiSite(); - $site->setGlobalId( 'eswiki' ); - $site->setLanguageCode( 'es' ); - $sites[] = $site; - - $this->assertCount( 0, $store->getSites(), '0 sites in store' ); - - $store->saveSites( $sites ); - - $this->assertCount( 2, $store->getSites(), 'Store has 2 sites' ); - $this->assertTrue( $store->getSites()->hasSite( 'enwiki' ), 'Store has enwiki' ); - $this->assertTrue( $store->getSites()->hasSite( 'eswiki' ), 'Store has eswiki' ); - } - - /** - * @covers HashSiteStore::clear - */ - public function testClear() { - $store = new HashSiteStore(); - - $site = new Site(); - $site->setGlobalId( 'arwiki' ); - $store->saveSite( $site ); - - $this->assertCount( 1, $store->getSites(), '1 site in store' ); - - $store->clear(); - $this->assertCount( 0, $store->getSites(), '0 sites in store' ); - } -} diff --git a/tests/phpunit/unit/includes/MediaWikiVersionFetcherTest.php b/tests/phpunit/unit/includes/MediaWikiVersionFetcherTest.php new file mode 100644 index 0000000000..dfdbfa7344 --- /dev/null +++ b/tests/phpunit/unit/includes/MediaWikiVersionFetcherTest.php @@ -0,0 +1,21 @@ + + */ +class MediaWikiVersionFetcherTest extends \MediaWikiUnitTestCase { + + public function testReturnsResult() { + global $wgVersion; + $versionFetcher = new MediaWikiVersionFetcher(); + $this->assertSame( $wgVersion, $versionFetcher->fetchVersion() ); + } + +} diff --git a/tests/phpunit/unit/includes/Rest/EntryPointTest.php b/tests/phpunit/unit/includes/Rest/EntryPointTest.php new file mode 100644 index 0000000000..e1f2c883a5 --- /dev/null +++ b/tests/phpunit/unit/includes/Rest/EntryPointTest.php @@ -0,0 +1,89 @@ +getMockBuilder( WebResponse::class ) + ->setMethods( [ 'header' ] ) + ->getMock(); + } + + public static function mockHandlerHeader() { + return new class extends Handler { + public function execute() { + $response = $this->getResponseFactory()->create(); + $response->setHeader( 'Foo', 'Bar' ); + return $response; + } + }; + } + + public function testHeader() { + $webResponse = $this->createWebResponse(); + $webResponse->expects( $this->any() ) + ->method( 'header' ) + ->withConsecutive( + [ 'HTTP/1.1 200 OK', true, null ], + [ 'Foo: Bar', true, null ] + ); + + $entryPoint = new EntryPoint( + new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/header' ) ] ), + $webResponse, + $this->createRouter() ); + $entryPoint->execute(); + $this->assertTrue( true ); + } + + public static function mockHandlerBodyRewind() { + return new class extends Handler { + public function execute() { + $response = $this->getResponseFactory()->create(); + $stream = new Stream( fopen( 'php://memory', 'w+' ) ); + $stream->write( 'hello' ); + $response->setBody( $stream ); + return $response; + } + }; + } + + /** + * Make sure EntryPoint rewinds a seekable body stream before reading. + */ + public function testBodyRewind() { + $entryPoint = new EntryPoint( + new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/bodyRewind' ) ] ), + $this->createWebResponse(), + $this->createRouter() ); + ob_start(); + $entryPoint->execute(); + $this->assertSame( 'hello', ob_get_clean() ); + } + +} diff --git a/tests/phpunit/unit/includes/Rest/Handler/HelloHandlerTest.php b/tests/phpunit/unit/includes/Rest/Handler/HelloHandlerTest.php new file mode 100644 index 0000000000..c68273b758 --- /dev/null +++ b/tests/phpunit/unit/includes/Rest/Handler/HelloHandlerTest.php @@ -0,0 +1,80 @@ + [ + [ + 'method' => 'GET', + 'uri' => self::makeUri( '/user/Tim/hello' ), + ], + [ + 'statusCode' => 200, + 'reasonPhrase' => 'OK', + 'protocolVersion' => '1.1', + 'body' => '{"message":"Hello, Tim!"}', + ], + ], + 'method not allowed' => [ + [ + 'method' => 'POST', + 'uri' => self::makeUri( '/user/Tim/hello' ), + ], + [ + 'statusCode' => 405, + 'reasonPhrase' => 'Method Not Allowed', + 'protocolVersion' => '1.1', + 'body' => '{"httpCode":405,"httpReason":"Method Not Allowed"}', + ], + ], + ]; + } + + private static function makeUri( $path ) { + return new Uri( "http://www.example.com/rest$path" ); + } + + /** @dataProvider provideTestViaRouter */ + public function testViaRouter( $requestInfo, $responseInfo ) { + $router = new Router( + [ __DIR__ . '/../testRoutes.json' ], + [], + '/rest', + new EmptyBagOStuff(), + new ResponseFactory() ); + $request = new RequestData( $requestInfo ); + $response = $router->execute( $request ); + if ( isset( $responseInfo['statusCode'] ) ) { + $this->assertSame( $responseInfo['statusCode'], $response->getStatusCode() ); + } + if ( isset( $responseInfo['reasonPhrase'] ) ) { + $this->assertSame( $responseInfo['reasonPhrase'], $response->getReasonPhrase() ); + } + if ( isset( $responseInfo['protocolVersion'] ) ) { + $this->assertSame( $responseInfo['protocolVersion'], $response->getProtocolVersion() ); + } + if ( isset( $responseInfo['body'] ) ) { + $this->assertSame( $responseInfo['body'], $response->getBody()->getContents() ); + } + $this->assertSame( + [], + array_diff( array_keys( $responseInfo ), [ + 'statusCode', + 'reasonPhrase', + 'protocolVersion', + 'body' + ] ), + '$responseInfo may not contain unknown keys' ); + } +} diff --git a/tests/phpunit/unit/includes/Rest/testRoutes.json b/tests/phpunit/unit/includes/Rest/testRoutes.json new file mode 100644 index 0000000000..7e43bb0c5d --- /dev/null +++ b/tests/phpunit/unit/includes/Rest/testRoutes.json @@ -0,0 +1,14 @@ +[ + { + "path": "/user/{name}/hello", + "class": "MediaWiki\\Rest\\Handler\\HelloHandler" + }, + { + "path": "/mock/EntryPoint/header", + "factory": "MediaWiki\\Tests\\Rest\\EntryPointTest::mockHandlerHeader" + }, + { + "path": "/mock/EntryPoint/bodyRewind", + "factory": "MediaWiki\\Tests\\Rest\\EntryPointTest::mockHandlerBodyRewind" + } +] diff --git a/tests/phpunit/unit/includes/Revision/RevisionStoreFactoryTest.php b/tests/phpunit/unit/includes/Revision/RevisionStoreFactoryTest.php new file mode 100644 index 0000000000..8e8fbd760f --- /dev/null +++ b/tests/phpunit/unit/includes/Revision/RevisionStoreFactoryTest.php @@ -0,0 +1,193 @@ +getMockLoadBalancerFactory(), + $this->getMockBlobStoreFactory(), + $this->getNameTableStoreFactory(), + $this->getMockSlotRoleRegistry(), + $this->getHashWANObjectCache(), + $this->getMockCommentStore(), + ActorMigration::newMigration(), + MIGRATION_OLD, + $this->getMockLoggerSpi(), + true + ); + $this->assertTrue( true ); + } + + public function provideWikiIds() { + yield [ true ]; + yield [ false ]; + yield [ 'somewiki' ]; + yield [ 'somewiki', MIGRATION_OLD , false ]; + yield [ 'somewiki', MIGRATION_NEW , true ]; + } + + /** + * @dataProvider provideWikiIds + * @covers \MediaWiki\Revision\RevisionStoreFactory::getRevisionStore + */ + public function testGetRevisionStore( + $dbDomain, + $mcrMigrationStage = MIGRATION_OLD, + $contentHandlerUseDb = true + ) { + $lbFactory = $this->getMockLoadBalancerFactory(); + $blobStoreFactory = $this->getMockBlobStoreFactory(); + $nameTableStoreFactory = $this->getNameTableStoreFactory(); + $slotRoleRegistry = $this->getMockSlotRoleRegistry(); + $cache = $this->getHashWANObjectCache(); + $commentStore = $this->getMockCommentStore(); + $actorMigration = ActorMigration::newMigration(); + $loggerProvider = $this->getMockLoggerSpi(); + + $factory = new RevisionStoreFactory( + $lbFactory, + $blobStoreFactory, + $nameTableStoreFactory, + $slotRoleRegistry, + $cache, + $commentStore, + $actorMigration, + $mcrMigrationStage, + $loggerProvider, + $contentHandlerUseDb + ); + + $store = $factory->getRevisionStore( $dbDomain ); + $wrapper = TestingAccessWrapper::newFromObject( $store ); + + // ensure the correct object type is returned + $this->assertInstanceOf( RevisionStore::class, $store ); + + // ensure the RevisionStore is for the given wikiId + $this->assertSame( $dbDomain, $wrapper->dbDomain ); + + // ensure all other required services are correctly set + $this->assertSame( $cache, $wrapper->cache ); + $this->assertSame( $commentStore, $wrapper->commentStore ); + $this->assertSame( $mcrMigrationStage, $wrapper->mcrMigrationStage ); + $this->assertSame( $actorMigration, $wrapper->actorMigration ); + $this->assertSame( $contentHandlerUseDb, $store->getContentHandlerUseDB() ); + + $this->assertInstanceOf( ILoadBalancer::class, $wrapper->loadBalancer ); + $this->assertInstanceOf( BlobStore::class, $wrapper->blobStore ); + $this->assertInstanceOf( NameTableStore::class, $wrapper->contentModelStore ); + $this->assertInstanceOf( NameTableStore::class, $wrapper->slotRoleStore ); + $this->assertInstanceOf( LoggerInterface::class, $wrapper->logger ); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|ILoadBalancer + */ + private function getMockLoadBalancer() { + return $this->getMockBuilder( ILoadBalancer::class ) + ->disableOriginalConstructor()->getMock(); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|ILBFactory + */ + private function getMockLoadBalancerFactory() { + $mock = $this->getMockBuilder( ILBFactory::class ) + ->disableOriginalConstructor()->getMock(); + + $mock->method( 'getMainLB' ) + ->willReturnCallback( function () { + return $this->getMockLoadBalancer(); + } ); + + return $mock; + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|SqlBlobStore + */ + private function getMockSqlBlobStore() { + return $this->getMockBuilder( SqlBlobStore::class ) + ->disableOriginalConstructor()->getMock(); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|BlobStoreFactory + */ + private function getMockBlobStoreFactory() { + $mock = $this->getMockBuilder( BlobStoreFactory::class ) + ->disableOriginalConstructor()->getMock(); + + $mock->method( 'newSqlBlobStore' ) + ->willReturnCallback( function () { + return $this->getMockSqlBlobStore(); + } ); + + return $mock; + } + + /** + * @return SlotRoleRegistry + */ + private function getMockSlotRoleRegistry() { + return $this->createMock( SlotRoleRegistry::class ); + } + + /** + * @return NameTableStoreFactory + */ + private function getNameTableStoreFactory() { + return new NameTableStoreFactory( + $this->getMockLoadBalancerFactory(), + $this->getHashWANObjectCache(), + new NullLogger() ); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|CommentStore + */ + private function getMockCommentStore() { + return $this->getMockBuilder( CommentStore::class ) + ->disableOriginalConstructor()->getMock(); + } + + private function getHashWANObjectCache() { + return new WANObjectCache( [ 'cache' => new \HashBagOStuff() ] ); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|LoggerSpi + */ + private function getMockLoggerSpi() { + $mock = $this->getMock( LoggerSpi::class ); + + $mock->method( 'getLogger' ) + ->willReturn( new NullLogger() ); + + return $mock; + } + +} diff --git a/tests/phpunit/unit/includes/config/ConfigFactoryTest.php b/tests/phpunit/unit/includes/config/ConfigFactoryTest.php new file mode 100644 index 0000000000..a136018c96 --- /dev/null +++ b/tests/phpunit/unit/includes/config/ConfigFactoryTest.php @@ -0,0 +1,168 @@ +register( 'unittest', 'GlobalVarConfig::newInstance' ); + $this->assertInstanceOf( GlobalVarConfig::class, $factory->makeConfig( 'unittest' ) ); + } + + /** + * @covers ConfigFactory::register + */ + public function testRegisterInvalid() { + $factory = new ConfigFactory(); + $this->setExpectedException( InvalidArgumentException::class ); + $factory->register( 'invalid', 'Invalid callback' ); + } + + /** + * @covers ConfigFactory::register + */ + public function testRegisterInvalidInstance() { + $factory = new ConfigFactory(); + $this->setExpectedException( InvalidArgumentException::class ); + $factory->register( 'invalidInstance', new stdClass ); + } + + /** + * @covers ConfigFactory::register + */ + public function testRegisterInstance() { + $config = GlobalVarConfig::newInstance(); + $factory = new ConfigFactory(); + $factory->register( 'unittest', $config ); + $this->assertSame( $config, $factory->makeConfig( 'unittest' ) ); + } + + /** + * @covers ConfigFactory::register + */ + public function testRegisterAgain() { + $factory = new ConfigFactory(); + $factory->register( 'unittest', 'GlobalVarConfig::newInstance' ); + $config1 = $factory->makeConfig( 'unittest' ); + + $factory->register( 'unittest', 'GlobalVarConfig::newInstance' ); + $config2 = $factory->makeConfig( 'unittest' ); + + $this->assertNotSame( $config1, $config2 ); + } + + /** + * @covers ConfigFactory::salvage + */ + public function testSalvage() { + $oldFactory = new ConfigFactory(); + $oldFactory->register( 'foo', 'GlobalVarConfig::newInstance' ); + $oldFactory->register( 'bar', 'GlobalVarConfig::newInstance' ); + $oldFactory->register( 'quux', 'GlobalVarConfig::newInstance' ); + + // instantiate two of the three defined configurations + $foo = $oldFactory->makeConfig( 'foo' ); + $bar = $oldFactory->makeConfig( 'bar' ); + $quux = $oldFactory->makeConfig( 'quux' ); + + // define new config instance + $newFactory = new ConfigFactory(); + $newFactory->register( 'foo', 'GlobalVarConfig::newInstance' ); + $newFactory->register( 'bar', function () { + return new HashConfig(); + } ); + + // "foo" and "quux" are defined in the old and the new factory. + // The old factory has instances for "foo" and "bar", but not "quux". + $newFactory->salvage( $oldFactory ); + + $newFoo = $newFactory->makeConfig( 'foo' ); + $this->assertSame( $foo, $newFoo, 'existing instance should be salvaged' ); + + $newBar = $newFactory->makeConfig( 'bar' ); + $this->assertNotSame( $bar, $newBar, 'don\'t salvage if callbacks differ' ); + + // the new factory doesn't have quux defined, so the quux instance should not be salvaged + $this->setExpectedException( ConfigException::class ); + $newFactory->makeConfig( 'quux' ); + } + + /** + * @covers ConfigFactory::getConfigNames + */ + public function testGetConfigNames() { + $factory = new ConfigFactory(); + $factory->register( 'foo', 'GlobalVarConfig::newInstance' ); + $factory->register( 'bar', new HashConfig() ); + + $this->assertEquals( [ 'foo', 'bar' ], $factory->getConfigNames() ); + } + + /** + * @covers ConfigFactory::makeConfig + */ + public function testMakeConfigWithCallback() { + $factory = new ConfigFactory(); + $factory->register( 'unittest', 'GlobalVarConfig::newInstance' ); + + $conf = $factory->makeConfig( 'unittest' ); + $this->assertInstanceOf( Config::class, $conf ); + $this->assertSame( $conf, $factory->makeConfig( 'unittest' ) ); + } + + /** + * @covers ConfigFactory::makeConfig + */ + public function testMakeConfigWithObject() { + $factory = new ConfigFactory(); + $conf = new HashConfig(); + $factory->register( 'test', $conf ); + $this->assertSame( $conf, $factory->makeConfig( 'test' ) ); + } + + /** + * @covers ConfigFactory::makeConfig + */ + public function testMakeConfigFallback() { + $factory = new ConfigFactory(); + $factory->register( '*', 'GlobalVarConfig::newInstance' ); + $conf = $factory->makeConfig( 'unittest' ); + $this->assertInstanceOf( Config::class, $conf ); + } + + /** + * @covers ConfigFactory::makeConfig + */ + public function testMakeConfigWithNoBuilders() { + $factory = new ConfigFactory(); + $this->setExpectedException( ConfigException::class ); + $factory->makeConfig( 'nobuilderregistered' ); + } + + /** + * @covers ConfigFactory::makeConfig + */ + public function testMakeConfigWithInvalidCallback() { + $factory = new ConfigFactory(); + $factory->register( 'unittest', function () { + return true; // Not a Config object + } ); + $this->setExpectedException( UnexpectedValueException::class ); + $factory->makeConfig( 'unittest' ); + } + + /** + * @covers ConfigFactory::getDefaultInstance + */ + public function testGetDefaultInstance() { + // NOTE: the global config factory returned here has been overwritten + // for operation in test mode. It may not reflect LocalSettings. + $factory = MediaWikiServices::getInstance()->getConfigFactory(); + $this->assertInstanceOf( Config::class, $factory->makeConfig( 'main' ) ); + } + +} diff --git a/tests/phpunit/unit/includes/media/GIFMetadataExtractorTest.php b/tests/phpunit/unit/includes/media/GIFMetadataExtractorTest.php new file mode 100644 index 0000000000..10c450d935 --- /dev/null +++ b/tests/phpunit/unit/includes/media/GIFMetadataExtractorTest.php @@ -0,0 +1,110 @@ +mediaPath = __DIR__ . '/../../../data/media/'; + } + + /** + * Put in a file, and see if the metadata coming out is as expected. + * @param string $filename + * @param array $expected The extracted metadata. + * @dataProvider provideGetMetadata + * @covers GIFMetadataExtractor::getMetadata + */ + public function testGetMetadata( $filename, $expected ) { + $actual = GIFMetadataExtractor::getMetadata( $this->mediaPath . $filename ); + $this->assertEquals( $expected, $actual ); + } + + public static function provideGetMetadata() { + $xmpNugget = << + + + + + The interwebs + + + + Bawolff + + + A file to test GIF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EOF; + $xmpNugget = str_replace( "\r", '', $xmpNugget ); // Windows compat + + return [ + [ + 'nonanimated.gif', + [ + 'comment' => [ 'GIF test file ⁕ Created with GIMP' ], + 'duration' => 0.1, + 'frameCount' => 1, + 'looped' => false, + 'xmp' => '', + ] + ], + [ + 'animated.gif', + [ + 'comment' => [ 'GIF test file . Created with GIMP' ], + 'duration' => 2.4, + 'frameCount' => 4, + 'looped' => true, + 'xmp' => '', + ] + ], + + [ + 'animated-xmp.gif', + [ + 'xmp' => $xmpNugget, + 'duration' => 2.4, + 'frameCount' => 4, + 'looped' => true, + 'comment' => [ 'GIƒ·test·file' ], + ] + ], + ]; + } +} diff --git a/tests/phpunit/unit/includes/media/SVGMetadataExtractorTest.php b/tests/phpunit/unit/includes/media/SVGMetadataExtractorTest.php new file mode 100644 index 0000000000..30d10083f4 --- /dev/null +++ b/tests/phpunit/unit/includes/media/SVGMetadataExtractorTest.php @@ -0,0 +1,201 @@ +assertMetadata( $infile, $expected ); + } + + /** + * @dataProvider provideSvgFilesWithXMLMetadata + */ + public function testGetXMLMetadata( $infile, $expected ) { + $r = new XMLReader(); + $this->assertMetadata( $infile, $expected ); + } + + /** + * @dataProvider provideSvgUnits + */ + public function testScaleSVGUnit( $inUnit, $expected ) { + $this->assertEquals( + $expected, + SVGReader::scaleSVGUnit( $inUnit ), + 'SVG unit conversion and scaling failure' + ); + } + + function assertMetadata( $infile, $expected ) { + try { + $data = SVGMetadataExtractor::getMetadata( $infile ); + $this->assertEquals( $expected, $data, 'SVG metadata extraction test' ); + } catch ( MWException $e ) { + if ( $expected === false ) { + $this->assertTrue( true, 'SVG metadata extracted test (expected failure)' ); + } else { + throw $e; + } + } + } + + public static function provideSvgFiles() { + $base = __DIR__ . '/../../../data/media'; + + return [ + [ + "$base/Wikimedia-logo.svg", + [ + 'width' => 1024, + 'height' => 1024, + 'originalWidth' => '1024', + 'originalHeight' => '1024', + 'translations' => [], + ] + ], + [ + "$base/QA_icon.svg", + [ + 'width' => 60, + 'height' => 60, + 'originalWidth' => '60', + 'originalHeight' => '60', + 'translations' => [], + ] + ], + [ + "$base/Gtk-media-play-ltr.svg", + [ + 'width' => 60, + 'height' => 60, + 'originalWidth' => '60.0000000', + 'originalHeight' => '60.0000000', + 'translations' => [], + ] + ], + [ + "$base/Toll_Texas_1.svg", + // This file triggered T33719, needs entity expansion in the xmlns checks + [ + 'width' => 385, + 'height' => 385, + 'originalWidth' => '385', + 'originalHeight' => '385.0004883', + 'translations' => [], + ] + ], + [ + "$base/Tux.svg", + [ + 'width' => 512, + 'height' => 594, + 'originalWidth' => '100%', + 'originalHeight' => '100%', + 'title' => 'Tux', + 'translations' => [], + 'description' => 'For more information see: http://commons.wikimedia.org/wiki/Image:Tux.svg', + ] + ], + [ + "$base/Speech_bubbles.svg", + [ + 'width' => 627, + 'height' => 461, + 'originalWidth' => '17.7cm', + 'originalHeight' => '13cm', + 'translations' => [ + 'de' => SVGReader::LANG_FULL_MATCH, + 'fr' => SVGReader::LANG_FULL_MATCH, + 'nl' => SVGReader::LANG_FULL_MATCH, + 'tlh-ca' => SVGReader::LANG_FULL_MATCH, + 'tlh' => SVGReader::LANG_PREFIX_MATCH + ], + ] + ], + [ + "$base/Soccer_ball_animated.svg", + [ + 'width' => 150, + 'height' => 150, + 'originalWidth' => '150', + 'originalHeight' => '150', + 'animated' => true, + 'translations' => [] + ], + ], + [ + "$base/comma_separated_viewbox.svg", + [ + 'width' => 512, + 'height' => 594, + 'originalWidth' => '100%', + 'originalHeight' => '100%', + 'translations' => [] + ], + ], + ]; + } + + public static function provideSvgFilesWithXMLMetadata() { + $base = __DIR__ . '/../../../data/media'; + // phpcs:disable Generic.Files.LineLength + $metadata = ' + + image/svg+xml + + + '; + // phpcs:enable + + $metadata = str_replace( "\r", '', $metadata ); // Windows compat + return [ + [ + "$base/US_states_by_total_state_tax_revenue.svg", + [ + 'height' => 593, + 'metadata' => $metadata, + 'width' => 959, + 'originalWidth' => '958.69', + 'originalHeight' => '592.78998', + 'translations' => [], + ] + ], + ]; + } + + public static function provideSvgUnits() { + return [ + [ '1' , 1 ], + [ '1.1' , 1.1 ], + [ '0.1' , 0.1 ], + [ '.1' , 0.1 ], + [ '1e2' , 100 ], + [ '1E2' , 100 ], + [ '+1' , 1 ], + [ '-1' , -1 ], + [ '-1.1' , -1.1 ], + [ '1e+2' , 100 ], + [ '1e-2' , 0.01 ], + [ '10px' , 10 ], + [ '10pt' , 10 * 1.25 ], + [ '10pc' , 10 * 15 ], + [ '10mm' , 10 * 3.543307 ], + [ '10cm' , 10 * 35.43307 ], + [ '10in' , 10 * 90 ], + [ '10em' , 10 * 16 ], + [ '10ex' , 10 * 12 ], + [ '10%' , 51.2 ], + [ '10 px' , 10 ], + // Invalid values + [ '1e1.1', 10 ], + [ '10bp', 10 ], + [ 'p10', null ], + ]; + } +} diff --git a/tests/phpunit/unit/includes/site/CachingSiteStoreTest.php b/tests/phpunit/unit/includes/site/CachingSiteStoreTest.php new file mode 100644 index 0000000000..92ed1f53e8 --- /dev/null +++ b/tests/phpunit/unit/includes/site/CachingSiteStoreTest.php @@ -0,0 +1,167 @@ + + */ +class CachingSiteStoreTest extends \MediaWikiUnitTestCase { + + /** + * @covers CachingSiteStore::getSites + */ + public function testGetSites() { + $testSites = TestSites::getSites(); + + $store = new CachingSiteStore( + $this->getHashSiteStore( $testSites ), + ObjectCache::getLocalClusterInstance() + ); + + $sites = $store->getSites(); + + $this->assertInstanceOf( SiteList::class, $sites ); + + /** + * @var Site $site + */ + foreach ( $sites as $site ) { + $this->assertInstanceOf( Site::class, $site ); + } + + foreach ( $testSites as $site ) { + if ( $site->getGlobalId() !== null ) { + $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) ); + } + } + } + + /** + * @covers CachingSiteStore::saveSites + */ + public function testSaveSites() { + $store = new CachingSiteStore( + new HashSiteStore(), ObjectCache::getLocalClusterInstance() + ); + + $sites = []; + + $site = new Site(); + $site->setGlobalId( 'ertrywuutr' ); + $site->setLanguageCode( 'en' ); + $sites[] = $site; + + $site = new MediaWikiSite(); + $site->setGlobalId( 'sdfhxujgkfpth' ); + $site->setLanguageCode( 'nl' ); + $sites[] = $site; + + $this->assertTrue( $store->saveSites( $sites ) ); + + $site = $store->getSite( 'ertrywuutr' ); + $this->assertInstanceOf( Site::class, $site ); + $this->assertEquals( 'en', $site->getLanguageCode() ); + + $site = $store->getSite( 'sdfhxujgkfpth' ); + $this->assertInstanceOf( Site::class, $site ); + $this->assertEquals( 'nl', $site->getLanguageCode() ); + } + + /** + * @covers CachingSiteStore::reset + */ + public function testReset() { + $dbSiteStore = $this->getMockBuilder( SiteStore::class ) + ->disableOriginalConstructor() + ->getMock(); + + $dbSiteStore->expects( $this->any() ) + ->method( 'getSite' ) + ->will( $this->returnValue( $this->getTestSite() ) ); + + $dbSiteStore->expects( $this->any() ) + ->method( 'getSites' ) + ->will( $this->returnCallback( function () { + $siteList = new SiteList(); + $siteList->setSite( $this->getTestSite() ); + + return $siteList; + } ) ); + + $store = new CachingSiteStore( $dbSiteStore, ObjectCache::getLocalClusterInstance() ); + + // initialize internal cache + $this->assertGreaterThan( 0, $store->getSites()->count(), 'count sites' ); + + $store->getSite( 'enwiki' )->setLanguageCode( 'en-ca' ); + + // sanity check: $store should have the new language code for 'enwiki' + $this->assertEquals( 'en-ca', $store->getSite( 'enwiki' )->getLanguageCode(), 'sanity check' ); + + // purge cache + $store->reset(); + + // the internal cache of $store should be updated, and now pulling + // the site from the 'fallback' DBSiteStore with the original language code. + $this->assertEquals( 'en', $store->getSite( 'enwiki' )->getLanguageCode(), 'reset' ); + } + + public function getTestSite() { + $enwiki = new MediaWikiSite(); + $enwiki->setGlobalId( 'enwiki' ); + $enwiki->setLanguageCode( 'en' ); + + return $enwiki; + } + + /** + * @covers CachingSiteStore::clear + */ + public function testClear() { + $store = new CachingSiteStore( + new HashSiteStore(), ObjectCache::getLocalClusterInstance() + ); + $this->assertTrue( $store->clear() ); + + $site = $store->getSite( 'enwiki' ); + $this->assertNull( $site ); + + $sites = $store->getSites(); + $this->assertEquals( 0, $sites->count() ); + } + + /** + * @param Site[] $sites + * + * @return SiteStore + */ + private function getHashSiteStore( array $sites ) { + $siteStore = new HashSiteStore(); + $siteStore->saveSites( $sites ); + + return $siteStore; + } + +} diff --git a/tests/phpunit/unit/includes/site/HashSiteStoreTest.php b/tests/phpunit/unit/includes/site/HashSiteStoreTest.php new file mode 100644 index 0000000000..8b0d4e080b --- /dev/null +++ b/tests/phpunit/unit/includes/site/HashSiteStoreTest.php @@ -0,0 +1,105 @@ + + */ +class HashSiteStoreTest extends \MediaWikiUnitTestCase { + + /** + * @covers HashSiteStore::getSites + */ + public function testGetSites() { + $expectedSites = []; + + foreach ( TestSites::getSites() as $testSite ) { + $siteId = $testSite->getGlobalId(); + $expectedSites[$siteId] = $testSite; + } + + $siteStore = new HashSiteStore( $expectedSites ); + + $this->assertEquals( new SiteList( $expectedSites ), $siteStore->getSites() ); + } + + /** + * @covers HashSiteStore::saveSite + * @covers HashSiteStore::getSite + */ + public function testSaveSite() { + $store = new HashSiteStore(); + + $site = new Site(); + $site->setGlobalId( 'dewiki' ); + + $this->assertCount( 0, $store->getSites(), '0 sites in store' ); + + $store->saveSite( $site ); + + $this->assertCount( 1, $store->getSites(), 'Store has 1 sites' ); + $this->assertEquals( $site, $store->getSite( 'dewiki' ), 'Store has dewiki' ); + } + + /** + * @covers HashSiteStore::saveSites + */ + public function testSaveSites() { + $store = new HashSiteStore(); + + $sites = []; + + $site = new Site(); + $site->setGlobalId( 'enwiki' ); + $site->setLanguageCode( 'en' ); + $sites[] = $site; + + $site = new MediaWikiSite(); + $site->setGlobalId( 'eswiki' ); + $site->setLanguageCode( 'es' ); + $sites[] = $site; + + $this->assertCount( 0, $store->getSites(), '0 sites in store' ); + + $store->saveSites( $sites ); + + $this->assertCount( 2, $store->getSites(), 'Store has 2 sites' ); + $this->assertTrue( $store->getSites()->hasSite( 'enwiki' ), 'Store has enwiki' ); + $this->assertTrue( $store->getSites()->hasSite( 'eswiki' ), 'Store has eswiki' ); + } + + /** + * @covers HashSiteStore::clear + */ + public function testClear() { + $store = new HashSiteStore(); + + $site = new Site(); + $site->setGlobalId( 'arwiki' ); + $store->saveSite( $site ); + + $this->assertCount( 1, $store->getSites(), '1 site in store' ); + + $store->clear(); + $this->assertCount( 0, $store->getSites(), '0 sites in store' ); + } +}