2014-09-03 16:52:33 +00:00
|
|
|
|
<?php
|
2019-05-01 13:56:41 +00:00
|
|
|
|
|
|
|
|
|
|
use MediaWiki\Config\ServiceOptions;
|
2023-01-30 03:53:09 +00:00
|
|
|
|
use MediaWiki\Tests\Unit\DummyServicesTrait;
|
2019-05-01 13:56:41 +00:00
|
|
|
|
use Psr\Log\NullLogger;
|
2023-08-04 10:33:22 +00:00
|
|
|
|
use Wikimedia\TestingAccessWrapper;
|
2019-05-01 13:56:41 +00:00
|
|
|
|
|
2014-09-03 16:52:33 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @group Database
|
|
|
|
|
|
* @group Cache
|
2024-02-16 18:04:47 +00:00
|
|
|
|
* @covers \LocalisationCache
|
2014-09-03 16:52:33 +00:00
|
|
|
|
* @author Niklas Laxström
|
|
|
|
|
|
*/
|
2020-06-30 15:09:24 +00:00
|
|
|
|
class LocalisationCacheTest extends MediaWikiIntegrationTestCase {
|
2023-01-30 03:53:09 +00:00
|
|
|
|
use DummyServicesTrait;
|
2014-09-03 16:52:33 +00:00
|
|
|
|
|
2014-12-03 22:12:52 +00:00
|
|
|
|
/**
|
Hooks::run() call site migration
Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.
General principles:
* Use DI if it is already used. We're not changing the way state is
managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
is a service, it's a more generic interface, it is the only
thing that provides isRegistered() which is needed in some cases,
and a HookRunner can be efficiently constructed from it
(confirmed by benchmark). Because HookContainer is needed
for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
SpecialPage and ApiBase have getHookContainer() and getHookRunner()
methods in the base class, and classes that extend that base class
are not expected to know or care where the base class gets its
HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
getHookRunner() methods, getting them from the global service
container. The point of this is to ease migration to DI by ensuring
that call sites ask their local friendly base class rather than
getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
methods did not seem warranted, there is a private HookRunner property
which is accessed directly. Very rarely (two cases), there is a
protected property, for consistency with code that conventionally
assumes protected=private, but in cases where the class might actually
be overridden, a protected accessor is preferred over a protected
property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
global code. In a few cases it was used for objects with broken
construction schemes, out of horror or laziness.
Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore
Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router
setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine
Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
2020-03-19 02:42:09 +00:00
|
|
|
|
* @param array $hooks Hook overrides
|
2023-07-28 14:30:52 +00:00
|
|
|
|
* @param array $options Service options (see {@link LocalisationCache::CONSTRUCTOR_OPTIONS})
|
2016-03-07 10:41:03 +00:00
|
|
|
|
* @return LocalisationCache
|
2014-12-03 22:12:52 +00:00
|
|
|
|
*/
|
2023-07-28 14:30:52 +00:00
|
|
|
|
protected function getMockLocalisationCache( $hooks = [], $options = [] ) {
|
2014-12-03 22:12:52 +00:00
|
|
|
|
global $IP;
|
2019-05-01 13:56:41 +00:00
|
|
|
|
|
Hooks::run() call site migration
Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.
General principles:
* Use DI if it is already used. We're not changing the way state is
managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
is a service, it's a more generic interface, it is the only
thing that provides isRegistered() which is needed in some cases,
and a HookRunner can be efficiently constructed from it
(confirmed by benchmark). Because HookContainer is needed
for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
SpecialPage and ApiBase have getHookContainer() and getHookRunner()
methods in the base class, and classes that extend that base class
are not expected to know or care where the base class gets its
HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
getHookRunner() methods, getting them from the global service
container. The point of this is to ease migration to DI by ensuring
that call sites ask their local friendly base class rather than
getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
methods did not seem warranted, there is a private HookRunner property
which is accessed directly. Very rarely (two cases), there is a
protected property, for consistency with code that conventionally
assumes protected=private, but in cases where the class might actually
be overridden, a protected accessor is preferred over a protected
property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
global code. In a few cases it was used for objects with broken
construction schemes, out of horror or laziness.
Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore
Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router
setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine
Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
2020-03-19 02:42:09 +00:00
|
|
|
|
$hookContainer = $this->createHookContainer( $hooks );
|
|
|
|
|
|
|
2023-01-30 03:53:09 +00:00
|
|
|
|
// in case any of the LanguageNameUtils hooks are being used
|
|
|
|
|
|
$langNameUtils = $this->getDummyLanguageNameUtils(
|
|
|
|
|
|
[ 'hookContainer' => $hookContainer ]
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2023-07-28 14:30:52 +00:00
|
|
|
|
$options += [
|
|
|
|
|
|
'forceRecache' => false,
|
|
|
|
|
|
'manualRecache' => false,
|
|
|
|
|
|
'ExtensionMessagesFiles' => [],
|
|
|
|
|
|
'MessagesDirs' => [],
|
2023-11-23 13:26:46 +00:00
|
|
|
|
'TranslationAliasesDirs' => [],
|
2023-07-28 14:30:52 +00:00
|
|
|
|
];
|
|
|
|
|
|
|
2019-05-01 13:56:41 +00:00
|
|
|
|
$lc = $this->getMockBuilder( LocalisationCache::class )
|
|
|
|
|
|
->setConstructorArgs( [
|
2023-07-28 14:30:52 +00:00
|
|
|
|
new ServiceOptions( LocalisationCache::CONSTRUCTOR_OPTIONS, $options ),
|
2019-05-01 13:56:41 +00:00
|
|
|
|
new LCStoreDB( [] ),
|
2019-05-02 14:23:42 +00:00
|
|
|
|
new NullLogger,
|
|
|
|
|
|
[],
|
2023-01-30 03:53:09 +00:00
|
|
|
|
$langNameUtils,
|
Hooks::run() call site migration
Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.
General principles:
* Use DI if it is already used. We're not changing the way state is
managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
is a service, it's a more generic interface, it is the only
thing that provides isRegistered() which is needed in some cases,
and a HookRunner can be efficiently constructed from it
(confirmed by benchmark). Because HookContainer is needed
for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
SpecialPage and ApiBase have getHookContainer() and getHookRunner()
methods in the base class, and classes that extend that base class
are not expected to know or care where the base class gets its
HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
getHookRunner() methods, getting them from the global service
container. The point of this is to ease migration to DI by ensuring
that call sites ask their local friendly base class rather than
getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
methods did not seem warranted, there is a private HookRunner property
which is accessed directly. Very rarely (two cases), there is a
protected property, for consistency with code that conventionally
assumes protected=private, but in cases where the class might actually
be overridden, a protected accessor is preferred over a protected
property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
global code. In a few cases it was used for objects with broken
construction schemes, out of horror or laziness.
Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore
Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router
setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine
Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
2020-03-19 02:42:09 +00:00
|
|
|
|
$hookContainer
|
2019-05-01 13:56:41 +00:00
|
|
|
|
] )
|
2021-03-20 15:18:58 +00:00
|
|
|
|
->onlyMethods( [ 'getMessagesDirs' ] )
|
2014-12-03 22:12:52 +00:00
|
|
|
|
->getMock();
|
2021-04-22 08:28:11 +00:00
|
|
|
|
$lc->method( 'getMessagesDirs' )
|
|
|
|
|
|
->willReturn( [ "$IP/tests/phpunit/data/localisationcache" ] );
|
2014-12-03 22:12:52 +00:00
|
|
|
|
|
|
|
|
|
|
return $lc;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-01 13:56:41 +00:00
|
|
|
|
public function testPluralRulesFallback() {
|
2014-12-03 22:12:52 +00:00
|
|
|
|
$cache = $this->getMockLocalisationCache();
|
2014-09-03 16:52:33 +00:00
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$cache->getItem( 'ar', 'pluralRules' ),
|
|
|
|
|
|
$cache->getItem( 'arz', 'pluralRules' ),
|
|
|
|
|
|
'arz plural rules (undefined) fallback to ar (defined)'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$cache->getItem( 'ar', 'compiledPluralRules' ),
|
|
|
|
|
|
$cache->getItem( 'arz', 'compiledPluralRules' ),
|
|
|
|
|
|
'arz compiled plural rules (undefined) fallback to ar (defined)'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertNotEquals(
|
|
|
|
|
|
$cache->getItem( 'ksh', 'pluralRules' ),
|
|
|
|
|
|
$cache->getItem( 'de', 'pluralRules' ),
|
|
|
|
|
|
'ksh plural rules (defined) dont fallback to de (defined)'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertNotEquals(
|
|
|
|
|
|
$cache->getItem( 'ksh', 'compiledPluralRules' ),
|
|
|
|
|
|
$cache->getItem( 'de', 'compiledPluralRules' ),
|
|
|
|
|
|
'ksh compiled plural rules (defined) dont fallback to de (defined)'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function testRecacheFallbacks() {
|
2014-12-03 22:12:52 +00:00
|
|
|
|
$lc = $this->getMockLocalisationCache();
|
2016-05-23 22:17:49 +00:00
|
|
|
|
$lc->recache( 'ba' );
|
LocalisationCache: Add tests for preload behavior
The new block in testRecacheExtensionMessagesFiles() covers the
underlying issue of T343343 and T343375; see change Icc3324aca7 for an
explanation of the issue.
In order for this test to not crash, we also need to adjust some of the
other tests and data. MessagesEn.php defines $preloadedMessages, and
LocalisationCache assumes (quite rightly so, really) that all of these
messages will be found in the configured MessagesDirs. But in the test,
we override MessagesDirs to point at the test’s JSON files, while still
using the original MessagesEn.php with its $preloadedMessages. Now that
we are triggering the preload mechanism (I think it wasn’t reached by
the tests previously?), it triggers a PHP deprecation (since PHP 8) on
the missing messages, which makes the test fail:
> explode(): Passing null to parameter #2 ($string) of type string is deprecated
I decided to fix this by adding fake entries for all $preloadedMessages
to the test en.json file. This makes the other tests that compare the
entire messages array fail, so instead only compare the three messages
those tests care about ("present-*"). I don’t like this very much, but I
dislike the other two approaches I can think of even more: check
defined( 'MW_PHPUNIT_TEST' ) in the original MessagesEn.php file, or add
a test-specific MessagesEn.php using the Language::getMessagesFileName
hook.
Bug: T342418
Bug: T343343
Bug: T343375
Change-Id: Iee11cb5c52cb9dd777b70a1daa06f41f2c3ca187
2023-08-04 10:22:07 +00:00
|
|
|
|
$messages = $lc->getItem( 'ba', 'messages' );
|
|
|
|
|
|
|
|
|
|
|
|
// Fallbacks are only used to fill missing data
|
|
|
|
|
|
$this->assertSame( 'ba', $messages['present-ba'] );
|
|
|
|
|
|
$this->assertSame( 'ru', $messages['present-ru'] );
|
|
|
|
|
|
$this->assertSame( 'en', $messages['present-en'] );
|
2014-09-03 16:52:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function testRecacheFallbacksWithHooks() {
|
|
|
|
|
|
// Use hook to provide updates for messages. This is what the
|
2017-02-20 23:45:58 +00:00
|
|
|
|
// LocalisationUpdate extension does. See T70781.
|
Hooks::run() call site migration
Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.
General principles:
* Use DI if it is already used. We're not changing the way state is
managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
is a service, it's a more generic interface, it is the only
thing that provides isRegistered() which is needed in some cases,
and a HookRunner can be efficiently constructed from it
(confirmed by benchmark). Because HookContainer is needed
for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
SpecialPage and ApiBase have getHookContainer() and getHookRunner()
methods in the base class, and classes that extend that base class
are not expected to know or care where the base class gets its
HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
getHookRunner() methods, getting them from the global service
container. The point of this is to ease migration to DI by ensuring
that call sites ask their local friendly base class rather than
getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
methods did not seem warranted, there is a private HookRunner property
which is accessed directly. Very rarely (two cases), there is a
protected property, for consistency with code that conventionally
assumes protected=private, but in cases where the class might actually
be overridden, a protected accessor is preferred over a protected
property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
global code. In a few cases it was used for objects with broken
construction schemes, out of horror or laziness.
Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore
Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router
setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine
Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
2020-03-19 02:42:09 +00:00
|
|
|
|
|
|
|
|
|
|
$lc = $this->getMockLocalisationCache( [
|
2023-03-28 19:56:37 +00:00
|
|
|
|
'LocalisationCacheRecacheFallback' =>
|
2021-02-07 13:10:36 +00:00
|
|
|
|
static function (
|
2014-10-15 15:39:27 +00:00
|
|
|
|
LocalisationCache $lc,
|
|
|
|
|
|
$code,
|
|
|
|
|
|
array &$cache
|
|
|
|
|
|
) {
|
|
|
|
|
|
if ( $code === 'ru' ) {
|
2016-05-23 22:17:49 +00:00
|
|
|
|
$cache['messages']['present-ba'] = 'ru-override';
|
2014-10-15 15:39:27 +00:00
|
|
|
|
$cache['messages']['present-ru'] = 'ru-override';
|
|
|
|
|
|
$cache['messages']['present-en'] = 'ru-override';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] );
|
2016-05-23 22:17:49 +00:00
|
|
|
|
$lc->recache( 'ba' );
|
LocalisationCache: Add tests for preload behavior
The new block in testRecacheExtensionMessagesFiles() covers the
underlying issue of T343343 and T343375; see change Icc3324aca7 for an
explanation of the issue.
In order for this test to not crash, we also need to adjust some of the
other tests and data. MessagesEn.php defines $preloadedMessages, and
LocalisationCache assumes (quite rightly so, really) that all of these
messages will be found in the configured MessagesDirs. But in the test,
we override MessagesDirs to point at the test’s JSON files, while still
using the original MessagesEn.php with its $preloadedMessages. Now that
we are triggering the preload mechanism (I think it wasn’t reached by
the tests previously?), it triggers a PHP deprecation (since PHP 8) on
the missing messages, which makes the test fail:
> explode(): Passing null to parameter #2 ($string) of type string is deprecated
I decided to fix this by adding fake entries for all $preloadedMessages
to the test en.json file. This makes the other tests that compare the
entire messages array fail, so instead only compare the three messages
those tests care about ("present-*"). I don’t like this very much, but I
dislike the other two approaches I can think of even more: check
defined( 'MW_PHPUNIT_TEST' ) in the original MessagesEn.php file, or add
a test-specific MessagesEn.php using the Language::getMessagesFileName
hook.
Bug: T342418
Bug: T343343
Bug: T343375
Change-Id: Iee11cb5c52cb9dd777b70a1daa06f41f2c3ca187
2023-08-04 10:22:07 +00:00
|
|
|
|
$messages = $lc->getItem( 'ba', 'messages' );
|
|
|
|
|
|
|
|
|
|
|
|
// Updates provided by hooks follow the normal fallback order.
|
|
|
|
|
|
$this->assertSame( 'ba', $messages['present-ba'] );
|
|
|
|
|
|
$this->assertSame( 'ru-override', $messages['present-ru'] );
|
|
|
|
|
|
$this->assertSame( 'ru-override', $messages['present-en'] );
|
2014-09-03 16:52:33 +00:00
|
|
|
|
}
|
2023-07-28 14:30:52 +00:00
|
|
|
|
|
|
|
|
|
|
public function testRecacheExtensionMessagesFiles(): void {
|
|
|
|
|
|
global $IP;
|
|
|
|
|
|
|
LocalisationCache: Add tests for preload behavior
The new block in testRecacheExtensionMessagesFiles() covers the
underlying issue of T343343 and T343375; see change Icc3324aca7 for an
explanation of the issue.
In order for this test to not crash, we also need to adjust some of the
other tests and data. MessagesEn.php defines $preloadedMessages, and
LocalisationCache assumes (quite rightly so, really) that all of these
messages will be found in the configured MessagesDirs. But in the test,
we override MessagesDirs to point at the test’s JSON files, while still
using the original MessagesEn.php with its $preloadedMessages. Now that
we are triggering the preload mechanism (I think it wasn’t reached by
the tests previously?), it triggers a PHP deprecation (since PHP 8) on
the missing messages, which makes the test fail:
> explode(): Passing null to parameter #2 ($string) of type string is deprecated
I decided to fix this by adding fake entries for all $preloadedMessages
to the test en.json file. This makes the other tests that compare the
entire messages array fail, so instead only compare the three messages
those tests care about ("present-*"). I don’t like this very much, but I
dislike the other two approaches I can think of even more: check
defined( 'MW_PHPUNIT_TEST' ) in the original MessagesEn.php file, or add
a test-specific MessagesEn.php using the Language::getMessagesFileName
hook.
Bug: T342418
Bug: T343343
Bug: T343375
Change-Id: Iee11cb5c52cb9dd777b70a1daa06f41f2c3ca187
2023-08-04 10:22:07 +00:00
|
|
|
|
// first, recache the l10n cache and test it
|
2023-07-28 14:30:52 +00:00
|
|
|
|
$lc = $this->getMockLocalisationCache( [], [
|
|
|
|
|
|
'ExtensionMessagesFiles' => [
|
|
|
|
|
|
__METHOD__ => "$IP/tests/phpunit/data/localisationcache/ExtensionMessagesFiles.php",
|
|
|
|
|
|
]
|
|
|
|
|
|
] );
|
|
|
|
|
|
$lc->recache( 'de' );
|
LocalisationCache: Add tests for preload behavior
The new block in testRecacheExtensionMessagesFiles() covers the
underlying issue of T343343 and T343375; see change Icc3324aca7 for an
explanation of the issue.
In order for this test to not crash, we also need to adjust some of the
other tests and data. MessagesEn.php defines $preloadedMessages, and
LocalisationCache assumes (quite rightly so, really) that all of these
messages will be found in the configured MessagesDirs. But in the test,
we override MessagesDirs to point at the test’s JSON files, while still
using the original MessagesEn.php with its $preloadedMessages. Now that
we are triggering the preload mechanism (I think it wasn’t reached by
the tests previously?), it triggers a PHP deprecation (since PHP 8) on
the missing messages, which makes the test fail:
> explode(): Passing null to parameter #2 ($string) of type string is deprecated
I decided to fix this by adding fake entries for all $preloadedMessages
to the test en.json file. This makes the other tests that compare the
entire messages array fail, so instead only compare the three messages
those tests care about ("present-*"). I don’t like this very much, but I
dislike the other two approaches I can think of even more: check
defined( 'MW_PHPUNIT_TEST' ) in the original MessagesEn.php file, or add
a test-specific MessagesEn.php using the Language::getMessagesFileName
hook.
Bug: T342418
Bug: T343343
Bug: T343375
Change-Id: Iee11cb5c52cb9dd777b70a1daa06f41f2c3ca187
2023-08-04 10:22:07 +00:00
|
|
|
|
$this->assertExtensionMessagesFiles( $lc );
|
|
|
|
|
|
|
|
|
|
|
|
// then, make another l10n cache sharing the first one’s LCStore and test that (T343375)
|
|
|
|
|
|
$lc = $this->getMockLocalisationCache( [], [
|
|
|
|
|
|
'ExtensionMessagesFiles' => [
|
|
|
|
|
|
__METHOD__ => "$IP/tests/phpunit/data/localisationcache/ExtensionMessagesFiles.php",
|
|
|
|
|
|
]
|
|
|
|
|
|
] );
|
|
|
|
|
|
// no recache this time, but load only the core data first by getting the fallbackSequence
|
|
|
|
|
|
$lc->getItem( 'de', 'fallbackSequence' );
|
|
|
|
|
|
$this->assertExtensionMessagesFiles( $lc );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-23 13:26:46 +00:00
|
|
|
|
public function testRecacheTranslationAliasesDirs(): void {
|
|
|
|
|
|
global $IP;
|
|
|
|
|
|
|
|
|
|
|
|
$lc = $this->getMockLocalisationCache( [], [
|
|
|
|
|
|
'TranslationAliasesDirs' => [
|
|
|
|
|
|
__METHOD__ => "$IP/tests/phpunit/data/localisationcache/translation-alias/"
|
|
|
|
|
|
]
|
|
|
|
|
|
] );
|
|
|
|
|
|
|
|
|
|
|
|
$lc->recache( 'nl' );
|
|
|
|
|
|
$specialPageAliases = $lc->getItem( 'nl', 'specialPageAliases' );
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
|
[ "Vertalersmeldingen(TEST)", "NotifyTranslators(TEST)" ],
|
|
|
|
|
|
$specialPageAliases['NotifyTranslators'],
|
|
|
|
|
|
'specialPageAliases can be set in TranslationAliasesDirs'
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
|
[ 'ActieveGebruikers(TEST)', 'ActieveGebruikers', 'ActiveUsers' ],
|
|
|
|
|
|
$specialPageAliases['Activeusers'],
|
|
|
|
|
|
'specialPageAliases from extension/core files are merged'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$lc->recache( 'pt' );
|
|
|
|
|
|
$specialPageAliases = $lc->getItem( 'pt', 'specialPageAliases' );
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
|
[ 'Utilizadores_activos(TEST)', 'Utilizadores_activos', 'Usuários_ativos', 'ActiveUsers' ],
|
|
|
|
|
|
$specialPageAliases['Activeusers'],
|
|
|
|
|
|
'specialPageAliases from extension/core files and fallback languages are merged'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$this->expectException( UnexpectedValueException::class );
|
|
|
|
|
|
$this->expectExceptionMessageMatches( '/invalid key:/i' );
|
|
|
|
|
|
$lc->recache( 'fr' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
LocalisationCache: Add tests for preload behavior
The new block in testRecacheExtensionMessagesFiles() covers the
underlying issue of T343343 and T343375; see change Icc3324aca7 for an
explanation of the issue.
In order for this test to not crash, we also need to adjust some of the
other tests and data. MessagesEn.php defines $preloadedMessages, and
LocalisationCache assumes (quite rightly so, really) that all of these
messages will be found in the configured MessagesDirs. But in the test,
we override MessagesDirs to point at the test’s JSON files, while still
using the original MessagesEn.php with its $preloadedMessages. Now that
we are triggering the preload mechanism (I think it wasn’t reached by
the tests previously?), it triggers a PHP deprecation (since PHP 8) on
the missing messages, which makes the test fail:
> explode(): Passing null to parameter #2 ($string) of type string is deprecated
I decided to fix this by adding fake entries for all $preloadedMessages
to the test en.json file. This makes the other tests that compare the
entire messages array fail, so instead only compare the three messages
those tests care about ("present-*"). I don’t like this very much, but I
dislike the other two approaches I can think of even more: check
defined( 'MW_PHPUNIT_TEST' ) in the original MessagesEn.php file, or add
a test-specific MessagesEn.php using the Language::getMessagesFileName
hook.
Bug: T342418
Bug: T343343
Bug: T343375
Change-Id: Iee11cb5c52cb9dd777b70a1daa06f41f2c3ca187
2023-08-04 10:22:07 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Assert that the given LocalisationCache, which should be configured with
|
|
|
|
|
|
* ExtensionMessagesFiles containing the ExtensionMessagesFiles.php test fixture file,
|
|
|
|
|
|
* contains the expected data.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function assertExtensionMessagesFiles( LocalisationCache $lc ): void {
|
2023-07-28 14:30:52 +00:00
|
|
|
|
$specialPageAliases = $lc->getItem( 'de', 'specialPageAliases' );
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
|
[ 'LokalisierungsPufferTest' ],
|
|
|
|
|
|
$specialPageAliases['LocalisationCacheTest'],
|
|
|
|
|
|
'specialPageAliases can be set in ExtensionMessagesFiles'
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
|
[ 'Aktive_Benutzer*innen', 'Aktive_Benutzer', 'ActiveFolx', 'ActiveUsers' ],
|
|
|
|
|
|
$specialPageAliases['Activeusers'],
|
|
|
|
|
|
'specialPageAliases from extension/core files and fallback languages are merged'
|
|
|
|
|
|
);
|
LocalisationCache: Add tests for preload behavior
The new block in testRecacheExtensionMessagesFiles() covers the
underlying issue of T343343 and T343375; see change Icc3324aca7 for an
explanation of the issue.
In order for this test to not crash, we also need to adjust some of the
other tests and data. MessagesEn.php defines $preloadedMessages, and
LocalisationCache assumes (quite rightly so, really) that all of these
messages will be found in the configured MessagesDirs. But in the test,
we override MessagesDirs to point at the test’s JSON files, while still
using the original MessagesEn.php with its $preloadedMessages. Now that
we are triggering the preload mechanism (I think it wasn’t reached by
the tests previously?), it triggers a PHP deprecation (since PHP 8) on
the missing messages, which makes the test fail:
> explode(): Passing null to parameter #2 ($string) of type string is deprecated
I decided to fix this by adding fake entries for all $preloadedMessages
to the test en.json file. This makes the other tests that compare the
entire messages array fail, so instead only compare the three messages
those tests care about ("present-*"). I don’t like this very much, but I
dislike the other two approaches I can think of even more: check
defined( 'MW_PHPUNIT_TEST' ) in the original MessagesEn.php file, or add
a test-specific MessagesEn.php using the Language::getMessagesFileName
hook.
Bug: T342418
Bug: T343343
Bug: T343375
Change-Id: Iee11cb5c52cb9dd777b70a1daa06f41f2c3ca187
2023-08-04 10:22:07 +00:00
|
|
|
|
$namespaceNames = $lc->getItem( 'de', 'namespaceNames' );
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
|
'LokalisierungsPufferTest',
|
|
|
|
|
|
$namespaceNames[98]
|
|
|
|
|
|
);
|
2023-07-21 09:31:43 +00:00
|
|
|
|
$this->assertFalse(
|
|
|
|
|
|
$lc->getItem( 'de', 'rtl' ),
|
|
|
|
|
|
'rtl cannot be set in ExtensionMessagesFiles'
|
|
|
|
|
|
);
|
2023-07-28 14:30:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-08-04 10:33:22 +00:00
|
|
|
|
public function testLoadCoreDataAvoidsInitLanguage(): void {
|
|
|
|
|
|
$lc = $this->getMockLocalisationCache();
|
|
|
|
|
|
|
|
|
|
|
|
$lc->getItem( 'de', 'fallback' );
|
|
|
|
|
|
$lc->getItem( 'de', 'rtl' );
|
|
|
|
|
|
$lc->getItem( 'de', 'fallbackSequence' );
|
|
|
|
|
|
$lc->getItem( 'de', 'originalFallbackSequence' );
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertArrayNotHasKey( 'de',
|
|
|
|
|
|
TestingAccessWrapper::newFromObject( $lc )->initialisedLangs );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-28 14:30:52 +00:00
|
|
|
|
public function testShallowFallbackForInvalidCode(): void {
|
|
|
|
|
|
$lc = $this->getMockLocalisationCache();
|
|
|
|
|
|
$invalidCode = '!invalid!';
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertSame( false, $lc->getItem( $invalidCode, 'rtl' ) );
|
|
|
|
|
|
$this->assertSame( 'windows-1252', $lc->getItem( $invalidCode, 'fallback8bitEncoding' ) );
|
|
|
|
|
|
}
|
2014-09-03 16:52:33 +00:00
|
|
|
|
}
|