getPageConfigMock(); $pageBundleMock = $this->getPageBundleMock( $pageBundleLanguageCode ); $languageVariantConverter = $this->getLanguageVariantConverter( $shouldParsoidBeUsed, $shouldPageConfigFactoryBeUsed, $isLanguageConversionEnabled, $pageBundleLanguageCode, null, $titleLanguageCode, $targetLanguageCode, $sourceLanguageCode, $parsoidSettings ); if ( !$shouldPageConfigFactoryBeUsed ) { $languageVariantConverter->setPageConfig( $pageConfigMock ); } $languageVariantConverter->convertPageBundleVariant( $pageBundleMock, $targetLanguageCode ); } public function provideSetConfig() { yield 'PageConfigFactory should not be used if PageConfig is set' => [ false ]; yield 'PageConfigFactory should be used if PageConfig is not set' => [ true ]; } /** @dataProvider provideSourceLanguage */ public function testSourceLanguage( ?string $pageBundleLanguageCode, ?string $titleLanguageCode, ?string $contentLanguageOverride, ?string $sourceLanguageCode, ?string $expectedSourceCode ) { // Decide what should be called and what should not be $shouldParsoidBeUsed = true; $shouldPageConfigFactoryBeUsed = true; $isLanguageConversionEnabled = true; // Set expected language codes $titleLanguageCode = $titleLanguageCode ?? 'en'; $targetLanguageCode = 'en-us'; $parsoidSettings = []; // Create mocks if ( $pageBundleLanguageCode ) { $pageBundleMock = $this->getPageBundleMock( $pageBundleLanguageCode ); } else { $pageBundleMock = $this->getPageBundleMockWithoutLanguage(); } $languageVariantConverter = $this->getLanguageVariantConverter( $shouldParsoidBeUsed, $shouldPageConfigFactoryBeUsed, $isLanguageConversionEnabled, $pageBundleLanguageCode, $contentLanguageOverride, $titleLanguageCode, $targetLanguageCode, $expectedSourceCode, $parsoidSettings ); $languageVariantConverter->convertPageBundleVariant( $pageBundleMock, $targetLanguageCode, $sourceLanguageCode ); } public function provideSourceLanguage() { yield 'content-language in PageBundle' => [ 'sr-el', // PageBundle content-language null, // Title PageLanguage null, // PageLanguage override 'sr-ec', // explicit source 'sr-ec' // expected source ]; yield 'content-language but no source language' => [ 'en', // PageBundle content-language null, // Title PageLanguage null, // PageLanguage override null, // explicit source null // expected source ]; yield 'content-language is variant' => [ 'en-ca', // PageBundle content-language null, // Title PageLanguage null, // PageLanguage override null, // explicit source 'en-ca' // expected source ]; yield 'Source variant is given' => [ null, // PageBundle content-language null, // Title PageLanguage null, // PageLanguage override 'en-ca', // explicit source 'en-ca' // expected source ]; yield 'Source variant is a base language' => [ null, // PageBundle content-language null, // Title PageLanguage null, // PageLanguage override 'en', // explicit source null // expected source ]; yield 'Page language override is variant' => [ null, // PageBundle content-language null, // PageBundle content-language 'en-ca', // PageLanguage override 'en-ca', // explicit source 'en-ca' // expected source ]; } /** @dataProvider provideSiteConfiguration */ public function testSiteConfiguration( bool $isLanguageConversionEnabled, bool $shouldParsoidBeUsed, bool $shouldPageConfigFactoryBeUsed ) { // Set expected language codes $pageBundleLanguageCode = 'zh'; $titleLanguageCode = 'zh-hans'; $targetLanguageCode = 'zh-hans'; $sourceLanguageCode = null; // Create mocks $parsoidSettings = []; if ( !$isLanguageConversionEnabled ) { $this->expectException( InvalidArgumentException::class ); $this->expectExceptionMessage( 'LanguageConversion is not supported' ); } $pageBundleMock = $this->getPageBundleMock( $pageBundleLanguageCode ); $languageVariantConverter = $this->getLanguageVariantConverter( $shouldParsoidBeUsed, $shouldPageConfigFactoryBeUsed, $isLanguageConversionEnabled, $pageBundleLanguageCode, null, $titleLanguageCode, $targetLanguageCode, $sourceLanguageCode, $parsoidSettings ); $languageVariantConverter->convertPageBundleVariant( $pageBundleMock, $targetLanguageCode ); } public function provideSiteConfiguration() { $isLanguageConversionEnabled = false; $shouldParsoidBeUsed = false; $shouldPageConfigFactoryBeUsed = false; yield 'If language conversion is disabled, parsoid and page config factory should not be used' => [ $isLanguageConversionEnabled, $shouldParsoidBeUsed, $shouldPageConfigFactoryBeUsed ]; $isLanguageConversionEnabled = true; $shouldParsoidBeUsed = true; $shouldPageConfigFactoryBeUsed = true; yield 'If language conversion is enabled, parsoid and page config factory should be used' => [ $isLanguageConversionEnabled, $shouldParsoidBeUsed, $shouldPageConfigFactoryBeUsed ]; } /** * @param bool $shouldParsoidBeUsed * @param bool $shouldPageConfigFactoryBeUsed * @param bool $isLanguageConversionEnabled * @param string|null $pageBundleLanguageCode * @param string|null $contentLanguageOverride * @param string $titleLanguageCode * @param string $targetLanguageCode * @param string|null $sourceLanguageCode * @param array $parsoidSettings * * @return LanguageVariantConverter */ private function getLanguageVariantConverter( bool $shouldParsoidBeUsed, bool $shouldPageConfigFactoryBeUsed, bool $isLanguageConversionEnabled, ?string $pageBundleLanguageCode, ?string $contentLanguageOverride, string $titleLanguageCode, string $targetLanguageCode, ?string $sourceLanguageCode, array $parsoidSettings ): LanguageVariantConverter { // If Content language is set, use language from there, // If PageBundle language code is set, use that // Else, fallback to title page language $pageLanguageCode = $contentLanguageOverride ?? $pageBundleLanguageCode ?? $titleLanguageCode; // The page language code should not be a variant $pageLanguageCode = preg_replace( '/-.*$/', '', $pageLanguageCode ); $shouldSiteConfigBeUsed = true; $parsoidSettings = []; $pageIdentityValue = new PageIdentityValue( 1, NS_MAIN, 'hello_world', PageIdentity::LOCAL ); // Create the necessary mocks $pageConfigMock = $this->getPageConfigMock(); $pageConfigFactoryMock = $this->getPageConfigFactoryMock( $shouldPageConfigFactoryBeUsed, // Expected arguments to PageConfigFactory mock [ $pageIdentityValue, null, null, null, $pageLanguageCode, $parsoidSettings ], $pageConfigMock ); $pageBundleMock = $this->getPageBundleMock( $pageBundleLanguageCode ); $siteConfigMock = $this->getSiteConfigMock( $shouldSiteConfigBeUsed, $pageLanguageCode, $isLanguageConversionEnabled ); $titleFactoryMock = $this->getTitleFactoryMock( $pageIdentityValue, $titleLanguageCode ); $languageFactoryMock = $this->getLanguageFactoryMock(); $parsoidMock = $this->getParsoidMock( $shouldParsoidBeUsed, [ $pageConfigMock, 'variant', $pageBundleMock, [ 'variant' => [ 'source' => $sourceLanguageCode, 'target' => $targetLanguageCode ] ] ] ); $languageVariantConverter = new LanguageVariantConverter( $pageIdentityValue, $pageConfigFactoryMock, $parsoidMock, $parsoidSettings, $siteConfigMock, $titleFactoryMock, $languageFactoryMock ); if ( $contentLanguageOverride ) { $languageVariantConverter->setPageLanguageOverride( $contentLanguageOverride ); } return $languageVariantConverter; } // Mock methods follow /** * @param bool $shouldBeCalled * @param array $arguments * @param PageConfig $pageConfig * * @return MockObject|PageConfigFactory */ private function getPageConfigFactoryMock( bool $shouldBeCalled, array $arguments, PageConfig $pageConfig ) { $mock = $this->createMock( PageConfigFactory::class ); if ( $shouldBeCalled ) { $mock->expects( $this->once() ) ->method( 'create' ) ->with( ...$arguments ) ->willReturn( $pageConfig ); } else { $mock->expects( $this->never() ) ->method( 'create' ); } return $mock; } /** * @param bool $shouldBeCalled * @param array $arguments * * @return MockObject|Parsoid */ private function getParsoidMock( bool $shouldBeCalled, array $arguments ) { $mock = $this->createMock( Parsoid::class ); if ( $shouldBeCalled ) { $mock->expects( $this->once() ) ->method( 'pb2pb' ) ->with( ...$arguments ); } else { $mock->expects( $this->never() ) ->method( 'pb2pb' ); } return $mock; } /** * @param bool $shouldBeCalled * @param string $baseLanguageCode * @param bool $isLanguageConversionEnabled * * @return MockObject|SiteConfig */ private function getSiteConfigMock( bool $shouldBeCalled, string $baseLanguageCode, bool $isLanguageConversionEnabled ) { $mock = $this->createMock( SiteConfig::class ); if ( $shouldBeCalled ) { $mock->expects( $this->once() ) ->method( 'langConverterEnabledForLanguage' ) ->with( $baseLanguageCode ) ->willReturn( $isLanguageConversionEnabled ); } else { $mock->expects( $this->never() ) ->method( 'langConverterEnabledForLanguage' ); } return $mock; } /** * @param PageIdentity $pageIdentity * @param string $languageCode * * @return MockObject|TitleFactory */ private function getTitleFactoryMock( PageIdentity $pageIdentity, string $languageCode ) { $languageMock = $this->getLanguageMock( $languageCode ); $titleMock = $this->createMock( Title::class ); $titleMock->method( 'getPageLanguage' ) ->willReturn( $languageMock ); $mock = $this->createMock( TitleFactory::class ); $mock->expects( $this->once() ) ->method( 'castFromPageIdentity' ) ->willReturn( $titleMock ) ->with( $pageIdentity ); return $mock; } /** * @return MockObject|LanguageFactory */ private function getLanguageFactoryMock() { $mock = $this->createMock( LanguageFactory::class ); $mock->method( 'getLanguage' ) ->willReturnCallback( function ( $code ) { return $this->getLanguageMock( $code ); } ); $mock->method( 'getParentLanguage' ) ->willReturnCallback( function ( $code ) { $code = preg_replace( '/-.*$/', '', $code ); return $this->getLanguageMock( $code ); } ); return $mock; } /** * @return MockObject|PageBundle */ private function getPageBundleMockWithoutLanguage() { return $this->getPageBundleMock( null ); } /** * @param string|null $languageCode * * @return MockObject|PageBundle */ private function getPageBundleMock( ?string $languageCode ) { $mock = $this->createMock( PageBundle::class ); $mock->headers = [ 'content-language' => $languageCode ]; return $mock; } /** * @return MockObject|PageConfig */ private function getPageConfigMock() { $mock = $this->createNoOpMock( PageConfig::class, [ 'setVariant' ] ); return $mock; } /** * @param string $languageCode * * @return MockObject|Language */ private function getLanguageMock( $languageCode ): Language { $languageMock = $this->createMock( Language::class ); $languageMock->method( 'getCode' ) ->willReturn( $languageCode ); return $languageMock; } }