2010-12-14 16:26:35 +00:00
|
|
|
|
<?php
|
|
|
|
|
|
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
use MediaWiki\Config\ServiceOptions;
|
2020-11-04 19:00:40 +00:00
|
|
|
|
use MediaWiki\HookContainer\HookContainer;
|
2020-01-23 18:39:23 +00:00
|
|
|
|
use MediaWiki\Languages\LanguageConverterFactory;
|
2018-08-07 13:17:16 +00:00
|
|
|
|
use MediaWiki\Languages\LanguageFallback;
|
|
|
|
|
|
use MediaWiki\Languages\LanguageNameUtils;
|
2019-11-17 09:52:02 +00:00
|
|
|
|
use MediaWiki\MediaWikiServices;
|
2021-10-15 17:39:56 +00:00
|
|
|
|
use MediaWiki\User\UserIdentityValue;
|
|
|
|
|
|
use Wikimedia\TestingAccessWrapper;
|
2018-08-01 12:40:47 +00:00
|
|
|
|
|
2020-01-23 18:39:23 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @group Language
|
|
|
|
|
|
*/
|
2019-08-25 12:45:34 +00:00
|
|
|
|
class LanguageIntegrationTest extends LanguageClassesTestCase {
|
2019-05-02 14:23:42 +00:00
|
|
|
|
use LanguageNameUtilsTestTrait;
|
|
|
|
|
|
|
|
|
|
|
|
/** @var array Copy of $wgHooks from before we unset LanguageGetTranslatedLanguageNames */
|
|
|
|
|
|
private $origHooks;
|
|
|
|
|
|
|
2018-08-07 13:17:16 +00:00
|
|
|
|
private function newLanguage( $class = Language::class, $code = 'en' ) {
|
|
|
|
|
|
return new $class(
|
|
|
|
|
|
$code,
|
|
|
|
|
|
$this->createNoOpMock( LocalisationCache::class ),
|
|
|
|
|
|
$this->createNoOpMock( LanguageNameUtils::class ),
|
|
|
|
|
|
$this->createNoOpMock( LanguageFallback::class ),
|
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
|
|
|
|
$this->createNoOpMock( LanguageConverterFactory::class ),
|
|
|
|
|
|
$this->createHookContainer()
|
2018-08-07 13:17:16 +00:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-22 03:11:47 +00:00
|
|
|
|
protected function setUp(): void {
|
2019-05-02 14:23:42 +00:00
|
|
|
|
global $wgHooks;
|
|
|
|
|
|
|
|
|
|
|
|
parent::setUp();
|
|
|
|
|
|
|
|
|
|
|
|
// Don't allow installed hooks to run, except if a test restores them via origHooks (needed
|
|
|
|
|
|
// for testIsKnownLanguageTag_cldr)
|
|
|
|
|
|
$this->origHooks = $wgHooks;
|
|
|
|
|
|
$newHooks = $wgHooks;
|
|
|
|
|
|
unset( $newHooks['LanguageGetTranslatedLanguageNames'] );
|
|
|
|
|
|
$this->setMwGlobals( 'wgHooks', $newHooks );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-10-22 10:32:29 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::convertDoubleWidth
|
|
|
|
|
|
* @covers Language::normalizeForSearch
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testLanguageConvertDoubleWidthToSingleWidth() {
|
2020-01-09 23:23:19 +00:00
|
|
|
|
$this->assertSame(
|
2010-12-14 16:26:35 +00:00
|
|
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
2012-10-23 20:53:17 +00:00
|
|
|
|
$this->getLang()->normalizeForSearch(
|
2010-12-14 16:26:35 +00:00
|
|
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
|
|
|
|
),
|
|
|
|
|
|
'convertDoubleWidth() with the full alphabet and digits'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2012-03-17 22:52:54 +00:00
|
|
|
|
|
2012-07-17 17:31:23 +00:00
|
|
|
|
/**
|
2014-04-18 17:10:38 +00:00
|
|
|
|
* @dataProvider provideFormattableTimes
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::formatTimePeriod
|
2012-07-17 17:31:23 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testFormatTimePeriod( $seconds, $format, $expected, $desc ) {
|
2012-10-23 20:53:17 +00:00
|
|
|
|
$this->assertEquals( $expected, $this->getLang()->formatTimePeriod( $seconds, $format ), $desc );
|
2011-09-23 22:02:36 +00:00
|
|
|
|
}
|
2012-03-17 22:52:54 +00:00
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideFormattableTimes() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
9.45,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[],
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'9.5 s',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (<10s)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
9.45,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'9.5 seconds',
|
|
|
|
|
|
'formatTimePeriod() rounding (<10s)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
9.95,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[],
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'10 s',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (<10s)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
9.95,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'10 seconds',
|
|
|
|
|
|
'formatTimePeriod() rounding (<10s)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
59.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[],
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'1 min 0 s',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (<60s)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
59.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'1 minute 0 seconds',
|
|
|
|
|
|
'formatTimePeriod() rounding (<60s)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
119.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[],
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'2 min 0 s',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (<1h)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
119.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'2 minutes 0 seconds',
|
|
|
|
|
|
'formatTimePeriod() rounding (<1h)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
3599.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[],
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'1 h 0 min 0 s',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (<1h)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
3599.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'1 hour 0 minutes 0 seconds',
|
|
|
|
|
|
'formatTimePeriod() rounding (<1h)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
7199.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[],
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'2 h 0 min 0 s',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (>=1h)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
7199.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'2 hours 0 minutes 0 seconds',
|
|
|
|
|
|
'formatTimePeriod() rounding (>=1h)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
7199.55,
|
|
|
|
|
|
'avoidseconds',
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'2 h 0 min',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (>=1h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
7199.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'2 hours 0 minutes',
|
|
|
|
|
|
'formatTimePeriod() rounding (>=1h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
7199.55,
|
|
|
|
|
|
'avoidminutes',
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'2 h 0 min',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (>=1h), avoidminutes'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
7199.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'avoid' => 'avoidminutes', 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'2 hours 0 minutes',
|
|
|
|
|
|
'formatTimePeriod() rounding (>=1h), avoidminutes'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
172799.55,
|
|
|
|
|
|
'avoidseconds',
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'48 h 0 min',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (=48h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
172799.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'48 hours 0 minutes',
|
|
|
|
|
|
'formatTimePeriod() rounding (=48h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2019-05-04 09:27:04 +00:00
|
|
|
|
[
|
|
|
|
|
|
259199.55,
|
|
|
|
|
|
'avoidhours',
|
|
|
|
|
|
'3 d',
|
|
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidhours'
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
|
|
|
|
|
259199.55,
|
|
|
|
|
|
[ 'avoid' => 'avoidhours', 'noabbrevs' => true ],
|
|
|
|
|
|
'3 days',
|
|
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidhours'
|
|
|
|
|
|
],
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
259199.55,
|
|
|
|
|
|
'avoidminutes',
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'3 d 0 h',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidminutes'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
259199.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'avoid' => 'avoidminutes', 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'3 days 0 hours',
|
|
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidminutes'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
176399.55,
|
|
|
|
|
|
'avoidseconds',
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'2 d 1 h 0 min',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
176399.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'2 days 1 hour 0 minutes',
|
|
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
176399.55,
|
|
|
|
|
|
'avoidminutes',
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'2 d 1 h',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidminutes'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
176399.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'avoid' => 'avoidminutes', 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'2 days 1 hour',
|
|
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidminutes'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
259199.55,
|
|
|
|
|
|
'avoidseconds',
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'3 d 0 h 0 min',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
259199.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'3 days 0 hours 0 minutes',
|
|
|
|
|
|
'formatTimePeriod() rounding (>48h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
172801.55,
|
|
|
|
|
|
'avoidseconds',
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'2 d 0 h 0 min',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding, (>48h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
172801.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'avoid' => 'avoidseconds', 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'2 days 0 hours 0 minutes',
|
|
|
|
|
|
'formatTimePeriod() rounding, (>48h), avoidseconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
176460.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[],
|
2012-09-27 18:24:19 +00:00
|
|
|
|
'2 d 1 h 1 min 1 s',
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'formatTimePeriod() rounding, recursion, (>48h)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-07-17 17:31:23 +00:00
|
|
|
|
176460.55,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'noabbrevs' => true ],
|
2012-07-17 17:31:23 +00:00
|
|
|
|
'2 days 1 hour 1 minute 1 second',
|
|
|
|
|
|
'formatTimePeriod() rounding, recursion, (>48h)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
];
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|
2011-03-03 19:13:57 +00:00
|
|
|
|
|
2013-10-22 10:32:29 +00:00
|
|
|
|
/**
|
2017-12-06 15:59:30 +00:00
|
|
|
|
* @covers Language::truncateForDatabase
|
|
|
|
|
|
* @covers Language::truncateInternal
|
2013-10-22 10:32:29 +00:00
|
|
|
|
*/
|
2017-12-06 15:59:30 +00:00
|
|
|
|
public function testTruncateForDatabase() {
|
2011-06-28 01:09:02 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"XXX",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "1234567890", 0, 'XXX' ),
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'truncate prefix, len 0, small ellipsis'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"12345XXX",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "1234567890", 8, 'XXX' ),
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'truncate prefix, small ellipsis'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2020-01-09 23:23:19 +00:00
|
|
|
|
$this->assertSame(
|
2011-06-28 01:09:02 +00:00
|
|
|
|
"123456789",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "123456789", 5, 'XXXXXXXXXXXXXXX' ),
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'truncate prefix, large ellipsis'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"XXX67890",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "1234567890", -8, 'XXX' ),
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'truncate suffix, small ellipsis'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2020-01-09 23:23:19 +00:00
|
|
|
|
$this->assertSame(
|
2011-06-28 01:09:02 +00:00
|
|
|
|
"123456789",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "123456789", -5, 'XXXXXXXXXXXXXXX' ),
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'truncate suffix, large ellipsis'
|
|
|
|
|
|
);
|
2013-11-10 08:55:10 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"123XXX",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "123 ", 9, 'XXX' ),
|
2013-11-10 08:55:10 +00:00
|
|
|
|
'truncate prefix, with spaces'
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"12345XXX",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "12345 8", 11, 'XXX' ),
|
2013-11-10 08:55:10 +00:00
|
|
|
|
'truncate prefix, with spaces and non-space ending'
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"XXX234",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "1 234", -8, 'XXX' ),
|
2013-11-10 08:55:10 +00:00
|
|
|
|
'truncate suffix, with spaces'
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"12345XXX",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "1234567890", 5, 'XXX', false ),
|
2013-11-10 08:55:10 +00:00
|
|
|
|
'truncate without adjustment'
|
|
|
|
|
|
);
|
2015-10-27 03:17:37 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"泰乐菌...",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "泰乐菌素123456789", 11, '...', false ),
|
2015-10-27 03:17:37 +00:00
|
|
|
|
'truncate does not chop Unicode characters in half'
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
"\n泰乐菌...",
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$this->getLang()->truncateForDatabase( "\n泰乐菌素123456789", 12, '...', false ),
|
2015-10-27 03:17:37 +00:00
|
|
|
|
'truncate does not chop Unicode characters in half if there is a preceding newline'
|
|
|
|
|
|
);
|
2011-06-28 01:09:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-06 15:59:30 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideTruncateData
|
|
|
|
|
|
* @covers Language::truncateForVisual
|
|
|
|
|
|
* @covers Language::truncateInternal
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testTruncateForVisual(
|
|
|
|
|
|
$expected, $string, $length, $ellipsis = '...', $adjustLength = true
|
|
|
|
|
|
) {
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$expected,
|
|
|
|
|
|
$this->getLang()->truncateForVisual( $string, $length, $ellipsis, $adjustLength )
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @return array Format is ($expected, $string, $length, $ellipsis, $adjustLength)
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function provideTruncateData() {
|
|
|
|
|
|
return [
|
|
|
|
|
|
[ "XXX", "тестирам да ли ради", 0, "XXX" ],
|
|
|
|
|
|
[ "testnXXX", "testni scenarij", 8, "XXX" ],
|
|
|
|
|
|
[ "حالة اختبار", "حالة اختبار", 5, "XXXXXXXXXXXXXXX" ],
|
|
|
|
|
|
[ "XXXедент", "прецедент", -8, "XXX" ],
|
|
|
|
|
|
[ "XXപിൾ", "ആപ്പിൾ", -5, "XX" ],
|
|
|
|
|
|
[ "神秘XXX", "神秘 ", 9, "XXX" ],
|
|
|
|
|
|
[ "ΔημιουργXXX", "Δημιουργία Σύμπαντος", 11, "XXX" ],
|
|
|
|
|
|
[ "XXXの家です", "地球は私たちの唯 の家です", -8, "XXX" ],
|
|
|
|
|
|
[ "زندگیXXX", "زندگی زیباست", 6, "XXX", false ],
|
|
|
|
|
|
[ "ცხოვრება...", "ცხოვრება არის საოცარი", 8, "...", false ],
|
|
|
|
|
|
[ "\nທ່ານ...", "\nທ່ານບໍ່ຮູ້ຫນັງສື", 5, "...", false ],
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-06-28 01:09:02 +00:00
|
|
|
|
/**
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @dataProvider provideHTMLTruncateData
|
|
|
|
|
|
* @covers Language::truncateHTML
|
2012-07-17 17:31:23 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testTruncateHtml( $len, $ellipsis, $input, $expected ) {
|
2011-06-28 01:09:02 +00:00
|
|
|
|
// Actual HTML...
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$expected,
|
2016-03-19 00:08:06 +00:00
|
|
|
|
$this->getLang()->truncateHtml( $input, $len, $ellipsis )
|
2011-06-28 01:09:02 +00:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-08-13 17:54:49 +00:00
|
|
|
|
* @return array Format is ($len, $ellipsis, $input, $expected)
|
2011-06-28 01:09:02 +00:00
|
|
|
|
*/
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideHTMLTruncateData() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ 0, 'XXX', "1234567890", "XXX" ],
|
|
|
|
|
|
[ 8, 'XXX', "1234567890", "12345XXX" ],
|
|
|
|
|
|
[ 5, 'XXXXXXXXXXXXXXX', '1234567890', "1234567890" ],
|
|
|
|
|
|
[ 2, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><span style="font-weight:bold;"></span></p>',
|
|
|
|
|
|
'<p><span style="font-weight:bold;"></span></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 2, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><span style="font-weight:bold;">123456789</span></p>',
|
|
|
|
|
|
'<p><span style="font-weight:bold;">***</span></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 2, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><span style="font-weight:bold;"> 23456789</span></p>',
|
|
|
|
|
|
'<p><span style="font-weight:bold;">***</span></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 3, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><span style="font-weight:bold;">123456789</span></p>',
|
|
|
|
|
|
'<p><span style="font-weight:bold;">***</span></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 4, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><span style="font-weight:bold;">123456789</span></p>',
|
|
|
|
|
|
'<p><span style="font-weight:bold;">1***</span></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 5, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<tt><span style="font-weight:bold;">123456789</span></tt>',
|
|
|
|
|
|
'<tt><span style="font-weight:bold;">12***</span></tt>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 6, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><a href="www.mediawiki.org">123456789</a></p>',
|
|
|
|
|
|
'<p><a href="www.mediawiki.org">123***</a></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 6, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><a href="www.mediawiki.org">12 456789</a></p>',
|
|
|
|
|
|
'<p><a href="www.mediawiki.org">12 ***</a></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 7, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<small><span style="font-weight:bold;">123<p id="#moo">456</p>789</span></small>',
|
|
|
|
|
|
'<small><span style="font-weight:bold;">123<p id="#moo">4***</p></span></small>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 8, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<div><span style="font-weight:bold;">123<span>4</span>56789</span></div>',
|
|
|
|
|
|
'<div><span style="font-weight:bold;">123<span>4</span>5***</span></div>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 9, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
|
|
|
|
|
|
'<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 10, '***',
|
2011-06-28 01:09:02 +00:00
|
|
|
|
'<p><font style="font-weight:bold;">123456789</font></p>',
|
|
|
|
|
|
'<p><font style="font-weight:bold;">123456789</font></p>',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
];
|
2011-06-28 01:09:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-01-21 04:44:09 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Test Language::isWellFormedLanguageTag()
|
|
|
|
|
|
* @dataProvider provideWellFormedLanguageTags
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::isWellFormedLanguageTag
|
2013-01-21 04:44:09 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testWellFormedLanguageTag( $code, $message = '' ) {
|
2013-01-21 04:44:09 +00:00
|
|
|
|
$this->assertTrue(
|
|
|
|
|
|
Language::isWellFormedLanguageTag( $code ),
|
|
|
|
|
|
"validating code $code $message"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* The test cases are based on the tests in the GaBuZoMeu parser
|
|
|
|
|
|
* written by Stéphane Bortzmeyer <bortzmeyer@nic.fr>
|
|
|
|
|
|
* and distributed as free software, under the GNU General Public Licence.
|
|
|
|
|
|
* http://www.bortzmeyer.org/gabuzomeu-parsing-language-tags.html
|
|
|
|
|
|
*/
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideWellFormedLanguageTags() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ 'fr', 'two-letter code' ],
|
|
|
|
|
|
[ 'fr-latn', 'two-letter code with lower case script code' ],
|
|
|
|
|
|
[ 'fr-Latn-FR', 'two-letter code with title case script code and uppercase country code' ],
|
|
|
|
|
|
[ 'fr-Latn-419', 'two-letter code with title case script code and region number' ],
|
|
|
|
|
|
[ 'fr-FR', 'two-letter code with uppercase' ],
|
|
|
|
|
|
[ 'ax-TZ', 'Not in the registry, but well-formed' ],
|
|
|
|
|
|
[ 'fr-shadok', 'two-letter code with variant' ],
|
|
|
|
|
|
[ 'fr-y-myext-myext2', 'non-x singleton' ],
|
|
|
|
|
|
[ 'fra-Latn', 'ISO 639 can be 3-letters' ],
|
|
|
|
|
|
[ 'fra', 'three-letter language code' ],
|
|
|
|
|
|
[ 'fra-FX', 'three-letter language code with country code' ],
|
|
|
|
|
|
[ 'i-klingon', 'grandfathered with singleton' ],
|
|
|
|
|
|
[ 'I-kLINgon', 'tags are case-insensitive...' ],
|
|
|
|
|
|
[ 'no-bok', 'grandfathered without singleton' ],
|
|
|
|
|
|
[ 'i-enochian', 'Grandfathered' ],
|
|
|
|
|
|
[ 'x-fr-CH', 'private use' ],
|
|
|
|
|
|
[ 'es-419', 'two-letter code with region number' ],
|
|
|
|
|
|
[ 'en-Latn-GB-boont-r-extended-sequence-x-private', 'weird, but well-formed' ],
|
|
|
|
|
|
[ 'ab-x-abc-x-abc', 'anything goes after x' ],
|
|
|
|
|
|
[ 'ab-x-abc-a-a', 'anything goes after x, including several non-x singletons' ],
|
|
|
|
|
|
[ 'i-default', 'grandfathered' ],
|
|
|
|
|
|
[ 'abcd-Latn', 'Language of 4 chars reserved for future use' ],
|
|
|
|
|
|
[ 'AaBbCcDd-x-y-any-x', 'Language of 5-8 chars, registered' ],
|
|
|
|
|
|
[ 'de-CH-1901', 'with country and year' ],
|
|
|
|
|
|
[ 'en-US-x-twain', 'with country and singleton' ],
|
|
|
|
|
|
[ 'zh-cmn', 'three-letter variant' ],
|
|
|
|
|
|
[ 'zh-cmn-Hant', 'three-letter variant and script' ],
|
|
|
|
|
|
[ 'zh-cmn-Hant-HK', 'three-letter variant, script and country' ],
|
|
|
|
|
|
[ 'xr-p-lze', 'Extension' ],
|
|
|
|
|
|
];
|
2013-01-21 04:44:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Negative test for Language::isWellFormedLanguageTag()
|
|
|
|
|
|
* @dataProvider provideMalformedLanguageTags
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::isWellFormedLanguageTag
|
2013-01-21 04:44:09 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testMalformedLanguageTag( $code, $message = '' ) {
|
2013-01-21 04:44:09 +00:00
|
|
|
|
$this->assertFalse(
|
|
|
|
|
|
Language::isWellFormedLanguageTag( $code ),
|
|
|
|
|
|
"validating that code $code is a malformed language tag - $message"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* The test cases are based on the tests in the GaBuZoMeu parser
|
|
|
|
|
|
* written by Stéphane Bortzmeyer <bortzmeyer@nic.fr>
|
|
|
|
|
|
* and distributed as free software, under the GNU General Public Licence.
|
|
|
|
|
|
* http://www.bortzmeyer.org/gabuzomeu-parsing-language-tags.html
|
|
|
|
|
|
*/
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideMalformedLanguageTags() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ 'f', 'language too short' ],
|
|
|
|
|
|
[ 'f-Latn', 'language too short with script' ],
|
|
|
|
|
|
[ 'xr-lxs-qut', 'variants too short' ], # extlangS
|
|
|
|
|
|
[ 'fr-Latn-F', 'region too short' ],
|
|
|
|
|
|
[ 'a-value', 'language too short with region' ],
|
|
|
|
|
|
[ 'tlh-a-b-foo', 'valid three-letter with wrong variant' ],
|
|
|
|
|
|
[
|
2014-04-24 17:52:34 +00:00
|
|
|
|
'i-notexist',
|
|
|
|
|
|
'grandfathered but not registered: invalid, even if we only test well-formedness'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[ 'abcdefghi-012345678', 'numbers too long' ],
|
|
|
|
|
|
[ 'ab-abc-abc-abc-abc', 'invalid extensions' ],
|
|
|
|
|
|
[ 'ab-abcd-abc', 'invalid extensions' ],
|
|
|
|
|
|
[ 'ab-ab-abc', 'invalid extensions' ],
|
|
|
|
|
|
[ 'ab-123-abc', 'invalid extensions' ],
|
|
|
|
|
|
[ 'a-Hant-ZH', 'short language with valid extensions' ],
|
|
|
|
|
|
[ 'a1-Hant-ZH', 'invalid character in language' ],
|
|
|
|
|
|
[ 'ab-abcde-abc', 'invalid extensions' ],
|
|
|
|
|
|
[ 'ab-1abc-abc', 'invalid characters in extensions' ],
|
|
|
|
|
|
[ 'ab-ab-abcd', 'invalid order of extensions' ],
|
|
|
|
|
|
[ 'ab-123-abcd', 'invalid order of extensions' ],
|
|
|
|
|
|
[ 'ab-abcde-abcd', 'invalid extensions' ],
|
|
|
|
|
|
[ 'ab-1abc-abcd', 'invalid characters in extensions' ],
|
|
|
|
|
|
[ 'ab-a-b', 'extensions too short' ],
|
|
|
|
|
|
[ 'ab-a-x', 'extensions too short, even with singleton' ],
|
|
|
|
|
|
[ 'ab--ab', 'two separators' ],
|
|
|
|
|
|
[ 'ab-abc-', 'separator in the end' ],
|
|
|
|
|
|
[ '-ab-abc', 'separator in the beginning' ],
|
|
|
|
|
|
[ 'abcd-efg', 'language too long' ],
|
|
|
|
|
|
[ 'aabbccddE', 'tag too long' ],
|
|
|
|
|
|
[ 'pa_guru', 'A tag with underscore is invalid in strict mode' ],
|
|
|
|
|
|
[ 'de-f', 'subtag too short' ],
|
|
|
|
|
|
];
|
2013-01-21 04:44:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Negative test for Language::isWellFormedLanguageTag()
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::isWellFormedLanguageTag
|
2013-01-21 04:44:09 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testLenientLanguageTag() {
|
2013-01-21 04:44:09 +00:00
|
|
|
|
$this->assertTrue(
|
|
|
|
|
|
Language::isWellFormedLanguageTag( 'pa_guru', true ),
|
|
|
|
|
|
'pa_guru is a well-formed language tag in lenient mode'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-04-25 07:58:39 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Test too short timestamp
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::sprintfDate
|
2013-04-25 07:58:39 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testSprintfDateTooShortTimestamp() {
|
2019-10-11 22:22:26 +00:00
|
|
|
|
$this->expectException( MWException::class );
|
2013-04-25 07:58:39 +00:00
|
|
|
|
$this->getLang()->sprintfDate( 'xiY', '1234567890123' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Test too long timestamp
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::sprintfDate
|
2013-04-25 07:58:39 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testSprintfDateTooLongTimestamp() {
|
2019-10-11 22:22:26 +00:00
|
|
|
|
$this->expectException( MWException::class );
|
2013-04-25 07:58:39 +00:00
|
|
|
|
$this->getLang()->sprintfDate( 'xiY', '123456789012345' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Test too short timestamp
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::sprintfDate
|
2013-04-25 07:58:39 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testSprintfDateNotAllDigitTimestamp() {
|
2019-10-11 22:22:26 +00:00
|
|
|
|
$this->expectException( MWException::class );
|
2013-04-25 07:58:39 +00:00
|
|
|
|
$this->getLang()->sprintfDate( 'xiY', '-1234567890123' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-12-14 00:32:56 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideSprintfDateSamples
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::sprintfDate
|
2011-12-14 00:32:56 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testSprintfDate( $format, $ts, $expected, $msg ) {
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$ttl = null;
|
2019-11-02 04:05:36 +00:00
|
|
|
|
$this->assertSame(
|
2011-12-14 00:32:56 +00:00
|
|
|
|
$expected,
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$this->getLang()->sprintfDate( $format, $ts, null, $ttl ),
|
2011-12-14 00:32:56 +00:00
|
|
|
|
"sprintfDate('$format', '$ts'): $msg"
|
|
|
|
|
|
);
|
2014-06-01 02:34:26 +00:00
|
|
|
|
if ( $ttl ) {
|
|
|
|
|
|
$dt = new DateTime( $ts );
|
|
|
|
|
|
$lastValidTS = $dt->add( new DateInterval( 'PT' . ( $ttl - 1 ) . 'S' ) )->format( 'YmdHis' );
|
2019-11-02 04:05:36 +00:00
|
|
|
|
$this->assertSame(
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$expected,
|
|
|
|
|
|
$this->getLang()->sprintfDate( $format, $lastValidTS, null ),
|
|
|
|
|
|
"sprintfDate('$format', '$ts'): TTL $ttl too high (output was different at $lastValidTS)"
|
|
|
|
|
|
);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// advance the time enough to make all of the possible outputs different (except possibly L)
|
|
|
|
|
|
$dt = new DateTime( $ts );
|
|
|
|
|
|
$newTS = $dt->add( new DateInterval( 'P1Y1M8DT13H1M1S' ) )->format( 'YmdHis' );
|
2019-11-02 04:05:36 +00:00
|
|
|
|
$this->assertSame(
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$expected,
|
|
|
|
|
|
$this->getLang()->sprintfDate( $format, $newTS, null ),
|
|
|
|
|
|
"sprintfDate('$format', '$ts'): Missing TTL (output was different at $newTS)"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2011-12-14 00:32:56 +00:00
|
|
|
|
}
|
2013-02-15 10:27:48 +00:00
|
|
|
|
|
2012-01-02 10:41:58 +00:00
|
|
|
|
/**
|
2013-03-22 16:41:03 +00:00
|
|
|
|
* sprintfDate should always use UTC when no zone is given.
|
2012-01-02 10:41:58 +00:00
|
|
|
|
* @dataProvider provideSprintfDateSamples
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::sprintfDate
|
2012-01-02 10:41:58 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testSprintfDateNoZone( $format, $ts, $expected, $ignore, $msg ) {
|
2012-01-02 10:41:58 +00:00
|
|
|
|
$oldTZ = date_default_timezone_get();
|
|
|
|
|
|
$res = date_default_timezone_set( 'Asia/Seoul' );
|
|
|
|
|
|
if ( !$res ) {
|
|
|
|
|
|
$this->markTestSkipped( "Error setting Timezone" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$expected,
|
2012-10-23 20:53:17 +00:00
|
|
|
|
$this->getLang()->sprintfDate( $format, $ts ),
|
2012-01-02 10:41:58 +00:00
|
|
|
|
"sprintfDate('$format', '$ts'): $msg"
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2012-03-17 22:52:54 +00:00
|
|
|
|
date_default_timezone_set( $oldTZ );
|
2012-01-02 10:41:58 +00:00
|
|
|
|
}
|
2011-12-14 00:32:56 +00:00
|
|
|
|
|
2013-03-22 16:41:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* sprintfDate should use passed timezone
|
|
|
|
|
|
* @dataProvider provideSprintfDateSamples
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::sprintfDate
|
2013-03-22 16:41:03 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testSprintfDateTZ( $format, $ts, $ignore, $expected, $msg ) {
|
2013-03-22 16:41:03 +00:00
|
|
|
|
$tz = new DateTimeZone( 'Asia/Seoul' );
|
|
|
|
|
|
if ( !$tz ) {
|
|
|
|
|
|
$this->markTestSkipped( "Error getting Timezone" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$expected,
|
|
|
|
|
|
$this->getLang()->sprintfDate( $format, $ts, $tz ),
|
|
|
|
|
|
"sprintfDate('$format', '$ts', 'Asia/Seoul'): $msg"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-06-23 10:01:59 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* sprintfDate should only calculate a TTL if the caller is going to use it.
|
|
|
|
|
|
* @covers Language::sprintfDate
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testSprintfDateNoTtlIfNotNeeded() {
|
|
|
|
|
|
$noTtl = 'unused'; // Value used to represent that the caller didn't pass a variable in.
|
|
|
|
|
|
$ttl = null;
|
|
|
|
|
|
$this->getLang()->sprintfDate( 'YmdHis', wfTimestampNow(), null, $noTtl );
|
|
|
|
|
|
$this->getLang()->sprintfDate( 'YmdHis', wfTimestampNow(), null, $ttl );
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
|
'unused',
|
|
|
|
|
|
$noTtl,
|
|
|
|
|
|
'If the caller does not set the $ttl variable, do not compute it.'
|
|
|
|
|
|
);
|
2019-12-13 14:29:10 +00:00
|
|
|
|
$this->assertIsInt( $ttl, 'TTL should have been computed.' );
|
2016-06-23 10:01:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideSprintfDateSamples() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[
|
2011-12-14 00:32:56 +00:00
|
|
|
|
'xiY',
|
|
|
|
|
|
'20111212000000',
|
|
|
|
|
|
'1390', // note because we're testing English locale we get Latin-standard digits
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'1390',
|
2011-12-14 00:32:56 +00:00
|
|
|
|
'Iranian calendar full year'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2011-12-14 00:32:56 +00:00
|
|
|
|
'xiy',
|
|
|
|
|
|
'20111212000000',
|
|
|
|
|
|
'90',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'90',
|
2011-12-14 00:32:56 +00:00
|
|
|
|
'Iranian calendar short year'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'o',
|
|
|
|
|
|
'20120101235000',
|
|
|
|
|
|
'2011',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'2011',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'ISO 8601 (week) year'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'W',
|
|
|
|
|
|
'20120101235000',
|
|
|
|
|
|
'52',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'52',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Week number'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'W',
|
|
|
|
|
|
'20120102235000',
|
2019-11-02 04:05:36 +00:00
|
|
|
|
'01',
|
|
|
|
|
|
'01',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Week number'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'o-\\WW-N',
|
|
|
|
|
|
'20091231235000',
|
|
|
|
|
|
'2009-W53-4',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'2009-W53-4',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'leap week'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2014-04-24 17:52:34 +00:00
|
|
|
|
// What follows is mostly copied from
|
|
|
|
|
|
// https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Y',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'2012',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'2012',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Full year'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'y',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'12',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'12',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'2 digit year'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'L',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'1',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'1',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Leap year'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'n',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'1',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'1',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Month index, not zero pad'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'N',
|
|
|
|
|
|
'20120102090705',
|
2019-11-02 04:05:36 +00:00
|
|
|
|
'1',
|
|
|
|
|
|
'1',
|
|
|
|
|
|
'Day of the week'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'M',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'Jan',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'Jan',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Month abbrev'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'F',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'January',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'January',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Full month'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xg',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'January',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'January',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Genitive month name (same in EN)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'j',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'2',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'2',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Day of month (not zero pad)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'd',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'02',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'02',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Day of month (zero-pad)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'z',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'1',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'1',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Day of year (zero-indexed)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'D',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'Mon',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'Mon',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Day of week (abbrev)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'l',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'Monday',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'Monday',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Full day of week'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'N',
|
|
|
|
|
|
'20120101090705',
|
|
|
|
|
|
'7',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'7',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Day of week (Mon=1, Sun=7)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'w',
|
|
|
|
|
|
'20120101090705',
|
|
|
|
|
|
'0',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'0',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Day of week (Sun=0, Sat=6)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'N',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'1',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'1',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Day of week'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'a',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'am',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'am',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'am vs pm'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'A',
|
|
|
|
|
|
'20120102120000',
|
|
|
|
|
|
'PM',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'PM',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'AM vs PM'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'a',
|
|
|
|
|
|
'20120102000000',
|
|
|
|
|
|
'am',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'am',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'AM vs PM'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'g',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'9',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'9',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'12 hour, not Zero'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'h',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'09',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'09',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'12 hour, zero padded'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'G',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'9',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'9',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'24 hour, not zero'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'H',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'09',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'09',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'24 hour, zero'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'H',
|
|
|
|
|
|
'20120102110705',
|
|
|
|
|
|
'11',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'11',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'24 hour, zero'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'i',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'07',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'07',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Minutes'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
's',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'05',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'05',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'seconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'U',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'1325495225',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'1325462825',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'unix time'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
't',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'31',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'31',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Days in current month'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'c',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'2012-01-02T09:07:05+00:00',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'2012-01-02T09:07:05+09:00',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'ISO 8601 timestamp'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'r',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'Mon, 02 Jan 2012 09:07:05 +0000',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'Mon, 02 Jan 2012 09:07:05 +0900',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'RFC 5322'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'e',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'UTC',
|
|
|
|
|
|
'Asia/Seoul',
|
|
|
|
|
|
'Timezone identifier'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'I',
|
|
|
|
|
|
'19880602090705',
|
|
|
|
|
|
'0',
|
|
|
|
|
|
'1',
|
|
|
|
|
|
'DST indicator'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'O',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'+0000',
|
|
|
|
|
|
'+0900',
|
|
|
|
|
|
'Timezone offset'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'P',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'+00:00',
|
|
|
|
|
|
'+09:00',
|
|
|
|
|
|
'Timezone offset with colon'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'T',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'UTC',
|
|
|
|
|
|
'KST',
|
|
|
|
|
|
'Timezone abbreviation'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'Z',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'0',
|
|
|
|
|
|
'32400',
|
|
|
|
|
|
'Timezone offset in seconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xmj xmF xmn xmY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'7 Safar 2 1433',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'7 Safar 2 1433',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Islamic'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xij xiF xin xiY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'12 Dey 10 1390',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'12 Dey 10 1390',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Iranian'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xjj xjF xjn xjY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'7 Tevet 4 5772',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'7 Tevet 4 5772',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Hebrew'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xjt',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'29',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'29',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Hebrew number of days in month'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xjx',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'Tevet',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'Tevet',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Hebrew genitive month name (No difference in EN)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xkY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'2555',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'2555',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Thai year'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2018-04-21 21:12:02 +00:00
|
|
|
|
[
|
|
|
|
|
|
'xkY',
|
|
|
|
|
|
'19410101090705',
|
|
|
|
|
|
'2484',
|
|
|
|
|
|
'2484',
|
|
|
|
|
|
'Thai year'
|
|
|
|
|
|
],
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xoY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'101',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'101',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Minguo'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xtY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'平成24',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'平成24',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'nengo'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2019-04-01 07:04:40 +00:00
|
|
|
|
[
|
|
|
|
|
|
'xtY',
|
|
|
|
|
|
'20190430235959',
|
|
|
|
|
|
'平成31',
|
|
|
|
|
|
'平成31',
|
|
|
|
|
|
'nengo - last day of heisei'
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
|
|
|
|
|
'xtY',
|
|
|
|
|
|
'20190501000000',
|
|
|
|
|
|
'令和元',
|
|
|
|
|
|
'令和元',
|
|
|
|
|
|
'nengo - first day of reiwa'
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
|
|
|
|
|
'xtY',
|
|
|
|
|
|
'20200501000000',
|
|
|
|
|
|
'令和2',
|
|
|
|
|
|
'令和2',
|
|
|
|
|
|
'nengo - second year of reiwa'
|
|
|
|
|
|
],
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xrxkYY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'MMDLV2012',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'MMDLV2012',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Roman numerals'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xhxjYY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'ה\'תשע"ב2012',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'ה\'תשע"ב2012',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Hebrew numberals'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'xnY',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'2012',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'2012',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Raw numerals (doesn\'t mean much in EN)'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'[[Y "(yea"\\r)]] \\"xx\\"',
|
|
|
|
|
|
'20120102090705',
|
|
|
|
|
|
'[[2012 (year)]] "x"',
|
2013-03-22 16:41:03 +00:00
|
|
|
|
'[[2012 (year)]] "x"',
|
2012-01-02 10:41:58 +00:00
|
|
|
|
'Various escaping'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2012-01-02 10:41:58 +00:00
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2011-12-14 00:32:56 +00:00
|
|
|
|
}
|
2011-12-31 02:13:59 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideFormatSizes
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::formatSize
|
2011-12-31 02:13:59 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testFormatSize( $size, $expected, $msg ) {
|
2011-12-31 02:13:59 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$expected,
|
2012-10-23 20:53:17 +00:00
|
|
|
|
$this->getLang()->formatSize( $size ),
|
2011-12-31 02:13:59 +00:00
|
|
|
|
"formatSize('$size'): $msg"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideFormatSizes() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[
|
2011-12-31 02:13:59 +00:00
|
|
|
|
0,
|
2015-08-30 05:23:13 +00:00
|
|
|
|
"0 bytes",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"Zero bytes"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2011-12-31 02:13:59 +00:00
|
|
|
|
1024,
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 KB",
|
|
|
|
|
|
"1 kilobyte"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2011-12-31 02:13:59 +00:00
|
|
|
|
1024 * 1024,
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 MB",
|
|
|
|
|
|
"1,024 megabytes"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2011-12-31 02:13:59 +00:00
|
|
|
|
1024 * 1024 * 1024,
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 GB",
|
2015-08-30 05:23:13 +00:00
|
|
|
|
"1 gigabyte"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
1024 ** 4,
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 TB",
|
|
|
|
|
|
"1 terabyte"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
1024 ** 5,
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 PB",
|
|
|
|
|
|
"1 petabyte"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
1024 ** 6,
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 EB",
|
|
|
|
|
|
"1,024 exabyte"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
1024 ** 7,
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 ZB",
|
2021-05-29 07:03:46 +00:00
|
|
|
|
"1 zettabyte"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
1024 ** 8,
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 YB",
|
|
|
|
|
|
"1 yottabyte"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2011-12-31 20:20:15 +00:00
|
|
|
|
// How big!? THIS BIG!
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2011-12-31 02:13:59 +00:00
|
|
|
|
}
|
2011-12-31 20:30:06 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideFormatBitrate
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::formatBitrate
|
2011-12-31 20:30:06 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testFormatBitrate( $bps, $expected, $msg ) {
|
2011-12-31 20:30:06 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$expected,
|
2012-10-23 20:53:17 +00:00
|
|
|
|
$this->getLang()->formatBitrate( $bps ),
|
2011-12-31 20:30:06 +00:00
|
|
|
|
"formatBitrate('$bps'): $msg"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideFormatBitrate() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[
|
2011-12-31 20:30:06 +00:00
|
|
|
|
0,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"0 bps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"0 bits per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-01-09 14:01:51 +00:00
|
|
|
|
999,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"999 bps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"999 bits per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2011-12-31 22:30:31 +00:00
|
|
|
|
1000,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1 kbps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 kilobit per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2011-12-31 22:30:31 +00:00
|
|
|
|
1000 * 1000,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1 Mbps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 megabit per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
10 ** 9,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1 Gbps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 gigabit per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
10 ** 12,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1 Tbps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 terabit per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
10 ** 15,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1 Pbps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 petabit per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
10 ** 18,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1 Ebps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 exabit per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
10 ** 21,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1 Zbps",
|
2021-05-29 07:03:46 +00:00
|
|
|
|
"1 zettabit per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
10 ** 24,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1 Ybps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1 yottabit per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2017-10-06 19:17:52 +00:00
|
|
|
|
10 ** 27,
|
2013-03-12 16:22:00 +00:00
|
|
|
|
"1,000 Ybps",
|
Revert r114067, r114071, r114075, r114079, r114081, r114082, r114084, r114086, r114088, r114089, r114101, r114118, r114137, r114147, r114164, r114172, r114175, r114180, r114208, r114209, r114215, r114219, r114226, r114321, r114322.
This reverts the SpecialCachedPage and formatDuration sagas, with some collateral damage here and there. All of these revisions are tagged with 'gerritmigration' and will be resubmitted into Gerrit after the Gerrit switchover. See also http://lists.wikimedia.org/pipermail/wikitech-l/2012-March/059124.html
2012-03-20 23:03:59 +00:00
|
|
|
|
"1,000 yottabits per second"
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
];
|
2012-03-17 22:39:38 +00:00
|
|
|
|
}
|
2012-04-10 13:37:03 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideFormatDuration
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::formatDuration
|
2012-04-10 13:37:03 +00:00
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
|
public function testFormatDuration( $duration, $expected, $intervals = [] ) {
|
2012-04-10 13:37:03 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$expected,
|
2012-10-23 20:53:17 +00:00
|
|
|
|
$this->getLang()->formatDuration( $duration, $intervals ),
|
2012-04-10 13:37:03 +00:00
|
|
|
|
"formatDuration('$duration'): $expected"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideFormatDuration() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
0,
|
|
|
|
|
|
'0 seconds',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
1,
|
|
|
|
|
|
'1 second',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
2,
|
|
|
|
|
|
'2 seconds',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
60,
|
|
|
|
|
|
'1 minute',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
2 * 60,
|
|
|
|
|
|
'2 minutes',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
3600,
|
|
|
|
|
|
'1 hour',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
2 * 3600,
|
|
|
|
|
|
'2 hours',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
24 * 3600,
|
|
|
|
|
|
'1 day',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
2 * 86400,
|
|
|
|
|
|
'2 days',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
// ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952
|
|
|
|
|
|
( 365 + ( 24 * 3 + 25 ) / 400.0 ) * 86400,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'1 year',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
2 * 31556952,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'2 years',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
10 * 31556952,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'1 decade',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
20 * 31556952,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'2 decades',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
100 * 31556952,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'1 century',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
200 * 31556952,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'2 centuries',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
1000 * 31556952,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'1 millennium',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
2000 * 31556952,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'2 millennia',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
9001,
|
|
|
|
|
|
'2 hours, 30 minutes and 1 second'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
3601,
|
|
|
|
|
|
'1 hour and 1 second'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
31556952 + 2 * 86400 + 9000,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'1 year, 2 days, 2 hours and 30 minutes'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
42 * 1000 * 31556952 + 42,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'42 millennia and 42 seconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
60,
|
|
|
|
|
|
'60 seconds',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'seconds' ],
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
61,
|
|
|
|
|
|
'61 seconds',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'seconds' ],
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
1,
|
|
|
|
|
|
'1 second',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'seconds' ],
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
31556952 + 2 * 86400 + 9000,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'1 year, 2 days and 150 minutes',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'years', 'days', 'minutes' ],
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
42,
|
|
|
|
|
|
'0 days',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'years', 'days' ],
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-12-29 14:07:21 +00:00
|
|
|
|
31556952 + 2 * 86400 + 9000,
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'1 year, 2 days and 150 minutes',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'minutes', 'days', 'years' ],
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-04-10 13:37:03 +00:00
|
|
|
|
42,
|
|
|
|
|
|
'0 days',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'days', 'years' ],
|
|
|
|
|
|
],
|
|
|
|
|
|
];
|
2012-04-10 13:37:03 +00:00
|
|
|
|
}
|
2012-06-05 22:58:54 +00:00
|
|
|
|
|
2012-07-17 17:31:23 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideCheckTitleEncodingData
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::checkTitleEncoding
|
2012-07-17 17:31:23 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testCheckTitleEncoding( $s ) {
|
2012-07-17 17:31:23 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$s,
|
2013-02-15 10:27:48 +00:00
|
|
|
|
$this->getLang()->checkTitleEncoding( $s ),
|
2012-07-17 17:31:23 +00:00
|
|
|
|
"checkTitleEncoding('$s')"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2012-06-05 22:58:54 +00:00
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideCheckTitleEncodingData() {
|
2016-03-19 01:05:19 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ "" ],
|
|
|
|
|
|
[ "United States of America" ], // 7bit ASCII
|
|
|
|
|
|
[ rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ],
|
|
|
|
|
|
[
|
2012-06-05 22:58:54 +00:00
|
|
|
|
rawurldecode(
|
|
|
|
|
|
"Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
|
|
|
|
|
|
)
|
2016-03-19 01:05:19 +00:00
|
|
|
|
],
|
2017-02-20 23:45:58 +00:00
|
|
|
|
// The following two data sets come from T38839. They fail if checkTitleEncoding uses a regexp to test for
|
2012-06-05 22:58:54 +00:00
|
|
|
|
// valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
|
2012-07-17 17:31:23 +00:00
|
|
|
|
// uses mb_check_encoding for its test.
|
2016-03-19 01:05:19 +00:00
|
|
|
|
[
|
2012-06-05 22:58:54 +00:00
|
|
|
|
rawurldecode(
|
|
|
|
|
|
"Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
|
2012-07-17 17:31:23 +00:00
|
|
|
|
. "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
|
|
|
|
|
|
. "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C"
|
|
|
|
|
|
. "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C"
|
|
|
|
|
|
. "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C"
|
|
|
|
|
|
. "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C"
|
|
|
|
|
|
. "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C"
|
|
|
|
|
|
. "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C"
|
|
|
|
|
|
. "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C"
|
|
|
|
|
|
. "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C"
|
|
|
|
|
|
. "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C"
|
|
|
|
|
|
. "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C"
|
|
|
|
|
|
. "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
|
|
|
|
|
|
. "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
|
2012-06-05 22:58:54 +00:00
|
|
|
|
),
|
2016-03-19 01:05:19 +00:00
|
|
|
|
],
|
|
|
|
|
|
[
|
2012-06-05 22:58:54 +00:00
|
|
|
|
rawurldecode(
|
|
|
|
|
|
"Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
|
2012-07-17 17:31:23 +00:00
|
|
|
|
. "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou"
|
|
|
|
|
|
. "%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
|
|
|
|
|
|
. "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
|
2012-06-05 22:58:54 +00:00
|
|
|
|
)
|
2016-03-19 01:05:19 +00:00
|
|
|
|
]
|
|
|
|
|
|
];
|
2018-01-01 13:10:16 +00:00
|
|
|
|
// phpcs:enable
|
2012-06-05 22:58:54 +00:00
|
|
|
|
}
|
2012-07-17 22:56:51 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideRomanNumeralsData
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::romanNumeral
|
2012-07-17 22:56:51 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testRomanNumerals( $num, $numerals ) {
|
2012-07-17 22:56:51 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$numerals,
|
|
|
|
|
|
Language::romanNumeral( $num ),
|
|
|
|
|
|
"romanNumeral('$num')"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideRomanNumeralsData() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ 1, 'I' ],
|
|
|
|
|
|
[ 2, 'II' ],
|
|
|
|
|
|
[ 3, 'III' ],
|
|
|
|
|
|
[ 4, 'IV' ],
|
|
|
|
|
|
[ 5, 'V' ],
|
|
|
|
|
|
[ 6, 'VI' ],
|
|
|
|
|
|
[ 7, 'VII' ],
|
|
|
|
|
|
[ 8, 'VIII' ],
|
|
|
|
|
|
[ 9, 'IX' ],
|
|
|
|
|
|
[ 10, 'X' ],
|
|
|
|
|
|
[ 20, 'XX' ],
|
|
|
|
|
|
[ 30, 'XXX' ],
|
|
|
|
|
|
[ 40, 'XL' ],
|
|
|
|
|
|
[ 49, 'XLIX' ],
|
|
|
|
|
|
[ 50, 'L' ],
|
|
|
|
|
|
[ 60, 'LX' ],
|
|
|
|
|
|
[ 70, 'LXX' ],
|
|
|
|
|
|
[ 80, 'LXXX' ],
|
|
|
|
|
|
[ 90, 'XC' ],
|
|
|
|
|
|
[ 99, 'XCIX' ],
|
|
|
|
|
|
[ 100, 'C' ],
|
|
|
|
|
|
[ 200, 'CC' ],
|
|
|
|
|
|
[ 300, 'CCC' ],
|
|
|
|
|
|
[ 400, 'CD' ],
|
|
|
|
|
|
[ 500, 'D' ],
|
|
|
|
|
|
[ 600, 'DC' ],
|
|
|
|
|
|
[ 700, 'DCC' ],
|
|
|
|
|
|
[ 800, 'DCCC' ],
|
|
|
|
|
|
[ 900, 'CM' ],
|
|
|
|
|
|
[ 999, 'CMXCIX' ],
|
|
|
|
|
|
[ 1000, 'M' ],
|
|
|
|
|
|
[ 1989, 'MCMLXXXIX' ],
|
|
|
|
|
|
[ 2000, 'MM' ],
|
|
|
|
|
|
[ 3000, 'MMM' ],
|
|
|
|
|
|
[ 4000, 'MMMM' ],
|
|
|
|
|
|
[ 5000, 'MMMMM' ],
|
|
|
|
|
|
[ 6000, 'MMMMMM' ],
|
|
|
|
|
|
[ 7000, 'MMMMMMM' ],
|
|
|
|
|
|
[ 8000, 'MMMMMMMM' ],
|
|
|
|
|
|
[ 9000, 'MMMMMMMMM' ],
|
|
|
|
|
|
[ 9999, 'MMMMMMMMMCMXCIX' ],
|
|
|
|
|
|
[ 10000, 'MMMMMMMMMM' ],
|
|
|
|
|
|
];
|
2012-07-17 22:56:51 +00:00
|
|
|
|
}
|
2012-09-16 19:13:03 +00:00
|
|
|
|
|
2015-05-04 21:27:35 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideHebrewNumeralsData
|
|
|
|
|
|
* @covers Language::hebrewNumeral
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testHebrewNumeral( $num, $numerals ) {
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$numerals,
|
|
|
|
|
|
Language::hebrewNumeral( $num ),
|
|
|
|
|
|
"hebrewNumeral('$num')"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static function provideHebrewNumeralsData() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ -1, -1 ],
|
|
|
|
|
|
[ 0, 0 ],
|
|
|
|
|
|
[ 1, "א'" ],
|
|
|
|
|
|
[ 2, "ב'" ],
|
|
|
|
|
|
[ 3, "ג'" ],
|
|
|
|
|
|
[ 4, "ד'" ],
|
|
|
|
|
|
[ 5, "ה'" ],
|
|
|
|
|
|
[ 6, "ו'" ],
|
|
|
|
|
|
[ 7, "ז'" ],
|
|
|
|
|
|
[ 8, "ח'" ],
|
|
|
|
|
|
[ 9, "ט'" ],
|
|
|
|
|
|
[ 10, "י'" ],
|
|
|
|
|
|
[ 11, 'י"א' ],
|
|
|
|
|
|
[ 14, 'י"ד' ],
|
|
|
|
|
|
[ 15, 'ט"ו' ],
|
|
|
|
|
|
[ 16, 'ט"ז' ],
|
|
|
|
|
|
[ 17, 'י"ז' ],
|
|
|
|
|
|
[ 20, "כ'" ],
|
|
|
|
|
|
[ 21, 'כ"א' ],
|
|
|
|
|
|
[ 30, "ל'" ],
|
|
|
|
|
|
[ 40, "מ'" ],
|
|
|
|
|
|
[ 50, "נ'" ],
|
|
|
|
|
|
[ 60, "ס'" ],
|
|
|
|
|
|
[ 70, "ע'" ],
|
|
|
|
|
|
[ 80, "פ'" ],
|
|
|
|
|
|
[ 90, "צ'" ],
|
|
|
|
|
|
[ 99, 'צ"ט' ],
|
|
|
|
|
|
[ 100, "ק'" ],
|
|
|
|
|
|
[ 101, 'ק"א' ],
|
|
|
|
|
|
[ 110, 'ק"י' ],
|
|
|
|
|
|
[ 200, "ר'" ],
|
|
|
|
|
|
[ 300, "ש'" ],
|
|
|
|
|
|
[ 400, "ת'" ],
|
|
|
|
|
|
[ 500, 'ת"ק' ],
|
|
|
|
|
|
[ 800, 'ת"ת' ],
|
|
|
|
|
|
[ 1000, "א' אלף" ],
|
|
|
|
|
|
[ 1001, "א'א'" ],
|
|
|
|
|
|
[ 1012, "א'י\"ב" ],
|
|
|
|
|
|
[ 1020, "א'ך'" ],
|
|
|
|
|
|
[ 1030, "א'ל'" ],
|
|
|
|
|
|
[ 1081, "א'פ\"א" ],
|
|
|
|
|
|
[ 2000, "ב' אלפים" ],
|
|
|
|
|
|
[ 2016, "ב'ט\"ז" ],
|
|
|
|
|
|
[ 3000, "ג' אלפים" ],
|
|
|
|
|
|
[ 4000, "ד' אלפים" ],
|
|
|
|
|
|
[ 4904, "ד'תתק\"ד" ],
|
|
|
|
|
|
[ 5000, "ה' אלפים" ],
|
|
|
|
|
|
[ 5680, "ה'תר\"ף" ],
|
|
|
|
|
|
[ 5690, "ה'תר\"ץ" ],
|
|
|
|
|
|
[ 5708, "ה'תש\"ח" ],
|
|
|
|
|
|
[ 5720, "ה'תש\"ך" ],
|
|
|
|
|
|
[ 5740, "ה'תש\"ם" ],
|
|
|
|
|
|
[ 5750, "ה'תש\"ן" ],
|
|
|
|
|
|
[ 5775, "ה'תשע\"ה" ],
|
|
|
|
|
|
];
|
2015-05-04 21:27:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-09-16 19:13:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider providePluralData
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::convertPlural
|
2012-09-16 19:13:03 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testConvertPlural( $expected, $number, $forms ) {
|
2012-10-23 20:53:17 +00:00
|
|
|
|
$chosen = $this->getLang()->convertPlural( $number, $forms );
|
2012-09-16 19:13:03 +00:00
|
|
|
|
$this->assertEquals( $expected, $chosen );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function providePluralData() {
|
2013-02-27 08:56:06 +00:00
|
|
|
|
// Params are: [expected text, number given, [the plural forms]]
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ 'plural', 0, [
|
2013-02-14 09:19:23 +00:00
|
|
|
|
'singular', 'plural'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ 'explicit zero', 0, [
|
2012-09-16 19:13:03 +00:00
|
|
|
|
'0=explicit zero', 'singular', 'plural'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ 'explicit one', 1, [
|
2012-09-16 19:13:03 +00:00
|
|
|
|
'singular', 'plural', '1=explicit one',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ 'singular', 1, [
|
2012-09-16 19:13:03 +00:00
|
|
|
|
'singular', 'plural', '0=explicit zero',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ 'plural', 3, [
|
2012-09-16 19:13:03 +00:00
|
|
|
|
'0=explicit zero', '1=explicit one', 'singular', 'plural'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ 'explicit eleven', 11, [
|
2013-02-27 08:56:06 +00:00
|
|
|
|
'singular', 'plural', '11=explicit eleven',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ 'plural', 12, [
|
2013-02-14 09:19:23 +00:00
|
|
|
|
'singular', 'plural', '11=explicit twelve',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ 'plural', 12, [
|
2013-02-14 09:19:23 +00:00
|
|
|
|
'singular', 'plural', '=explicit form',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ 'other', 2, [
|
2013-02-27 08:56:06 +00:00
|
|
|
|
'kissa=kala', '1=2=3', 'other',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
[ '', 2, [
|
2013-05-25 23:19:55 +00:00
|
|
|
|
'0=explicit zero', '1=explicit one',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
] ],
|
|
|
|
|
|
];
|
2012-09-16 19:13:03 +00:00
|
|
|
|
}
|
2012-11-20 12:13:37 +00:00
|
|
|
|
|
2015-06-29 21:48:41 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::embedBidi()
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testEmbedBidi() {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
$lre = "\u{202A}"; // U+202A LEFT-TO-RIGHT EMBEDDING
|
|
|
|
|
|
$rle = "\u{202B}"; // U+202B RIGHT-TO-LEFT EMBEDDING
|
|
|
|
|
|
$pdf = "\u{202C}"; // U+202C POP DIRECTIONAL FORMATTING
|
2015-06-29 21:48:41 +00:00
|
|
|
|
$lang = $this->getLang();
|
2020-01-09 23:23:19 +00:00
|
|
|
|
$this->assertSame(
|
2015-06-29 21:48:41 +00:00
|
|
|
|
'123',
|
|
|
|
|
|
$lang->embedBidi( '123' ),
|
|
|
|
|
|
'embedBidi with neutral argument'
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$lre . 'Ben_(WMF)' . $pdf,
|
|
|
|
|
|
$lang->embedBidi( 'Ben_(WMF)' ),
|
|
|
|
|
|
'embedBidi with LTR argument'
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$rle . 'יהודי (מנוחין)' . $pdf,
|
|
|
|
|
|
$lang->embedBidi( 'יהודי (מנוחין)' ),
|
|
|
|
|
|
'embedBidi with RTL argument'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-11-20 12:13:37 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::translateBlockExpiry()
|
|
|
|
|
|
* @dataProvider provideTranslateBlockExpiry
|
|
|
|
|
|
*/
|
2017-01-27 08:51:06 +00:00
|
|
|
|
public function testTranslateBlockExpiry( $expectedData, $str, $now, $desc ) {
|
2012-11-20 12:13:37 +00:00
|
|
|
|
$lang = $this->getLang();
|
|
|
|
|
|
if ( is_array( $expectedData ) ) {
|
|
|
|
|
|
list( $func, $arg ) = $expectedData;
|
|
|
|
|
|
$expected = $lang->$func( $arg );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$expected = $expectedData;
|
|
|
|
|
|
}
|
2019-11-02 04:05:36 +00:00
|
|
|
|
// HACK:
|
|
|
|
|
|
date_default_timezone_set( 'UTC' );
|
|
|
|
|
|
$this->assertSame( $expected, $lang->translateBlockExpiry( $str, null, $now ), $desc );
|
2012-11-20 12:13:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideTranslateBlockExpiry() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
2017-01-27 08:51:06 +00:00
|
|
|
|
[ '2 hours', '2 hours', 0, 'simple data from ipboptions' ],
|
|
|
|
|
|
[ 'indefinite', 'infinite', 0, 'infinite from ipboptions' ],
|
|
|
|
|
|
[ 'indefinite', 'infinity', 0, 'alternative infinite from ipboptions' ],
|
|
|
|
|
|
[ 'indefinite', 'indefinite', 0, 'another alternative infinite from ipboptions' ],
|
|
|
|
|
|
[ [ 'formatDuration', 1023 * 60 * 60 ], '1023 hours', 0, 'relative' ],
|
|
|
|
|
|
[ [ 'formatDuration', -1023 ], '-1023 seconds', 0, 'negative relative' ],
|
|
|
|
|
|
[
|
|
|
|
|
|
[ 'formatDuration', 1023 * 60 * 60 ],
|
|
|
|
|
|
'1023 hours',
|
|
|
|
|
|
wfTimestamp( TS_UNIX, '19910203040506' ),
|
|
|
|
|
|
'relative with initial timestamp'
|
|
|
|
|
|
],
|
|
|
|
|
|
[ [ 'formatDuration', 0 ], 'now', 0, 'now' ],
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
|
|
|
|
|
[ 'timeanddate', '20120102070000' ],
|
2014-04-24 17:52:34 +00:00
|
|
|
|
'2012-1-1 7:00 +1 day',
|
2017-01-27 08:51:06 +00:00
|
|
|
|
0,
|
2014-04-24 17:52:34 +00:00
|
|
|
|
'mixed, handled as absolute'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
2017-01-27 08:51:06 +00:00
|
|
|
|
[ [ 'timeanddate', '19910203040506' ], '1991-2-3 4:05:06', 0, 'absolute' ],
|
|
|
|
|
|
[ [ 'timeanddate', '19700101000000' ], '1970-1-1 0:00:00', 0, 'absolute at epoch' ],
|
|
|
|
|
|
[ [ 'timeanddate', '19691231235959' ], '1969-12-31 23:59:59', 0, 'time before epoch' ],
|
|
|
|
|
|
[
|
|
|
|
|
|
[ 'timeanddate', '19910910000000' ],
|
|
|
|
|
|
'10 september',
|
|
|
|
|
|
wfTimestamp( TS_UNIX, '19910203040506' ),
|
|
|
|
|
|
'partial'
|
|
|
|
|
|
],
|
|
|
|
|
|
[ 'dummy', 'dummy', 0, 'return garbage as is' ],
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2012-11-20 12:13:37 +00:00
|
|
|
|
}
|
2012-11-27 19:09:04 +00:00
|
|
|
|
|
2017-12-06 22:55:08 +00:00
|
|
|
|
/**
|
2017-12-28 08:24:40 +00:00
|
|
|
|
* @dataProvider provideFormatNum
|
2017-12-06 22:55:08 +00:00
|
|
|
|
* @covers Language::formatNum
|
2017-06-02 08:42:28 +00:00
|
|
|
|
* @covers Language::formatNumNoSeparators
|
2017-12-06 22:55:08 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function testFormatNum(
|
2017-06-02 08:42:28 +00:00
|
|
|
|
$translateNumerals, $langCode, $number, $noSeparators, $expected
|
2017-12-06 22:55:08 +00:00
|
|
|
|
) {
|
2017-06-02 08:42:28 +00:00
|
|
|
|
$this->hideDeprecated( 'Language::formatNum with a non-numeric string' );
|
2017-12-06 22:55:08 +00:00
|
|
|
|
$this->setMwGlobals( [ 'wgTranslateNumerals' => $translateNumerals ] );
|
|
|
|
|
|
$lang = Language::factory( $langCode );
|
2017-06-02 08:42:28 +00:00
|
|
|
|
if ( $noSeparators ) {
|
|
|
|
|
|
$formattedNum = $lang->formatNumNoSeparators( $number );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$formattedNum = $lang->formatNum( $number );
|
|
|
|
|
|
}
|
2019-12-13 17:44:39 +00:00
|
|
|
|
$this->assertIsString( $formattedNum );
|
2017-12-06 22:55:08 +00:00
|
|
|
|
$this->assertEquals( $expected, $formattedNum );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-28 08:24:40 +00:00
|
|
|
|
public function provideFormatNum() {
|
2017-12-06 22:55:08 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ true, 'en', 100, false, '100' ],
|
|
|
|
|
|
[ true, 'en', 101, true, '101' ],
|
|
|
|
|
|
[ false, 'en', 103, false, '103' ],
|
|
|
|
|
|
[ false, 'en', 104, true, '104' ],
|
2017-06-02 08:42:28 +00:00
|
|
|
|
[ true, 'en', '105', false, '105' ],
|
|
|
|
|
|
[ true, 'en', '106', true, '106' ],
|
|
|
|
|
|
[ false, 'en', '107', false, '107' ],
|
|
|
|
|
|
[ false, 'en', '108', true, '108' ],
|
2020-10-21 13:57:50 +00:00
|
|
|
|
[ true, 'en', -1, false, '−1' ],
|
2017-06-02 08:42:28 +00:00
|
|
|
|
[ true, 'en', 10, false, '10' ],
|
|
|
|
|
|
[ true, 'en', 100, false, '100' ],
|
|
|
|
|
|
[ true, 'en', 1000, false, '1,000' ],
|
|
|
|
|
|
[ true, 'en', 10000, false, '10,000' ],
|
|
|
|
|
|
[ true, 'en', 100000, false, '100,000' ],
|
|
|
|
|
|
[ true, 'en', 1000000, false, '1,000,000' ],
|
2020-10-21 13:57:50 +00:00
|
|
|
|
[ true, 'en', -1.001, false, '−1.001' ],
|
2017-06-02 08:42:28 +00:00
|
|
|
|
[ true, 'en', 1.001, false, '1.001' ],
|
|
|
|
|
|
[ true, 'en', 10.0001, false, '10.0001' ],
|
|
|
|
|
|
[ true, 'en', 100.001, false, '100.001' ],
|
|
|
|
|
|
[ true, 'en', 1000.001, false, '1,000.001' ],
|
|
|
|
|
|
[ true, 'en', 10000.001, false, '10,000.001' ],
|
|
|
|
|
|
[ true, 'en', 100000.001, false, '100,000.001' ],
|
|
|
|
|
|
[ true, 'en', 1000000.0001, false, '1,000,000.0001' ],
|
2020-10-21 13:57:50 +00:00
|
|
|
|
[ true, 'en', -1.0001, false, '−1.0001' ],
|
2017-06-02 08:42:28 +00:00
|
|
|
|
[ true, 'en', '200000000000000000000', false, '200,000,000,000,000,000,000' ],
|
2020-10-21 13:57:50 +00:00
|
|
|
|
[ true, 'en', '-200000000000000000000', false, '−200,000,000,000,000,000,000' ],
|
2020-11-11 00:18:09 +00:00
|
|
|
|
[ true, 'en', '1.23e10', false, '12,300,000,000' ],
|
|
|
|
|
|
[ true, 'en', 1.23e10, false, '12,300,000,000' ],
|
|
|
|
|
|
[ true, 'en', '1.23E-01', false, '0.123' ],
|
|
|
|
|
|
[ true, 'en', 1.23e-1, false, '0.123' ],
|
2020-10-21 13:57:50 +00:00
|
|
|
|
[ true, 'en', 0.0, false, '0' ],
|
|
|
|
|
|
[ true, 'en', -0.0, false, '−0' ],
|
2020-11-09 22:04:41 +00:00
|
|
|
|
[ true, 'en', INF, false, '∞' ],
|
|
|
|
|
|
[ true, 'en', -INF, false, '−∞' ],
|
|
|
|
|
|
[ true, 'en', NAN, false, 'Not a Number' ],
|
Language: ensure commafy does not corrupt UTF-8 strings
The commafy method "should" be given valid numeric strings, but this
wasn't enforced, and if were provided input which started with a UTF-8
multibyte character and then had a single ASCII digit somewhere after
that, it would return the first byte of the input string, resulting in
an invalid UTF-8 sequence.
Fix this bug with belt and suspenders: first, enforce the expected
input structure at the top of the function. Since there is existing
code which expects us to "do our best" with invalid input, split the
input string into valid numeric chunks before processing it. This
split code triggers a hard deprecation warning, so we can eventually
remove it.
Second, make the sign test more robust and anchor the $integerPart
regexp to match assumptions made in the algorithm, so that even if
bogus input *did* creep through (a sloppy future maintainer, say) it
wouldn't lead to corrupt UTF-8 in the output.
Add test cases covering these conditions, borrowing liberally from
I741b70757e43b1312c86719920e29885566e916c, which points out that while
commafy expects numeric strings, formatNum replaces – character by
character – digits and separator characters with language specific
ones. Optionally thousand separators are added (a.k.a. "commafy").
Eventually we should tighten the spec for formatNum as well; some of
this has already been done in
I03ffa99f7de1dcc48535ba1e1251567dbf3db116 and
I89b17a9e11b3afc6c653ba7ccc6ff84c37863b66.
Some additional test case fixes borrowed from
If45ef33a50b2623322f17306d123f0d8cb468618 which updated a few test
cases to be more specific, i.e. actually test stuff (for example,
commafy doesn't happen on 3-digit numbers, and numerals are not
translated in English).
Bug: T237467
Depends-On: I89b17a9e11b3afc6c653ba7ccc6ff84c37863b66
Depends-On: I9dcbe91fa926dba1cfd24d9bf075ee1ebef36b9e
Depends-On: I03ffa99f7de1dcc48535ba1e1251567dbf3db116
Change-Id: If3dcfd71acd8ebf3eea6a49408260f2aaa07e469
2020-09-08 23:19:41 +00:00
|
|
|
|
[ true, 'kn', '1050', false, '೧,೦೫೦' ],
|
|
|
|
|
|
[ true, 'kn', '1060', true, '೧೦೬೦' ],
|
|
|
|
|
|
[ false, 'kn', '1070', false, '1,070' ],
|
|
|
|
|
|
[ false, 'kn', '1080', true, '1080' ],
|
|
|
|
|
|
[ true, 'kn', '.1090', false, '.೧೦೯೦' ],
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure non-numeric strings are not destroyed
|
|
|
|
|
|
[ false, 'en', 'The number is 1234', false, 'The number is 1,234' ],
|
|
|
|
|
|
[ false, 'en', '1234 is the number', false, '1,234 is the number' ],
|
2017-06-02 08:42:28 +00:00
|
|
|
|
[ false, 'de', '.', false, '.' ],
|
|
|
|
|
|
[ false, 'de', ',', false, ',' ],
|
Language: ensure commafy does not corrupt UTF-8 strings
The commafy method "should" be given valid numeric strings, but this
wasn't enforced, and if were provided input which started with a UTF-8
multibyte character and then had a single ASCII digit somewhere after
that, it would return the first byte of the input string, resulting in
an invalid UTF-8 sequence.
Fix this bug with belt and suspenders: first, enforce the expected
input structure at the top of the function. Since there is existing
code which expects us to "do our best" with invalid input, split the
input string into valid numeric chunks before processing it. This
split code triggers a hard deprecation warning, so we can eventually
remove it.
Second, make the sign test more robust and anchor the $integerPart
regexp to match assumptions made in the algorithm, so that even if
bogus input *did* creep through (a sloppy future maintainer, say) it
wouldn't lead to corrupt UTF-8 in the output.
Add test cases covering these conditions, borrowing liberally from
I741b70757e43b1312c86719920e29885566e916c, which points out that while
commafy expects numeric strings, formatNum replaces – character by
character – digits and separator characters with language specific
ones. Optionally thousand separators are added (a.k.a. "commafy").
Eventually we should tighten the spec for formatNum as well; some of
this has already been done in
I03ffa99f7de1dcc48535ba1e1251567dbf3db116 and
I89b17a9e11b3afc6c653ba7ccc6ff84c37863b66.
Some additional test case fixes borrowed from
If45ef33a50b2623322f17306d123f0d8cb468618 which updated a few test
cases to be more specific, i.e. actually test stuff (for example,
commafy doesn't happen on 3-digit numbers, and numerals are not
translated in English).
Bug: T237467
Depends-On: I89b17a9e11b3afc6c653ba7ccc6ff84c37863b66
Depends-On: I9dcbe91fa926dba1cfd24d9bf075ee1ebef36b9e
Depends-On: I03ffa99f7de1dcc48535ba1e1251567dbf3db116
Change-Id: If3dcfd71acd8ebf3eea6a49408260f2aaa07e469
2020-09-08 23:19:41 +00:00
|
|
|
|
|
|
|
|
|
|
/** @see https://phabricator.wikimedia.org/T237467 */
|
|
|
|
|
|
[ false, 'kn', "೭\u{FFFD}0", false, "೭\u{FFFD}0" ],
|
|
|
|
|
|
[ false, 'kn', "-೭\u{FFFD}0", false, "-೭\u{FFFD}0" ],
|
2020-10-21 13:57:50 +00:00
|
|
|
|
[ false, 'kn', "-1೭\u{FFFD}0", false, "−1೭\u{FFFD}0" ],
|
2020-11-10 18:00:00 +00:00
|
|
|
|
|
|
|
|
|
|
/** @see https://phabricator.wikimedia.org/T267614 */
|
|
|
|
|
|
[ false, 'ar', "1", false, "1" ],
|
|
|
|
|
|
[ false, 'ar', "1234.5", false, "1٬234٫5" ],
|
|
|
|
|
|
[ true, 'ar', "1", false, "١" ],
|
|
|
|
|
|
[ true, 'ar', "1234.5", false, "١٬٢٣٤٫٥" ],
|
2017-12-06 22:55:08 +00:00
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-04-24 02:33:58 +00:00
|
|
|
|
/**
|
2017-12-28 08:24:40 +00:00
|
|
|
|
* @covers Language::parseFormattedNumber
|
2014-04-24 02:33:58 +00:00
|
|
|
|
* @dataProvider parseFormattedNumberProvider
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testParseFormattedNumber( $langCode, $number ) {
|
|
|
|
|
|
$lang = Language::factory( $langCode );
|
|
|
|
|
|
|
|
|
|
|
|
$localisedNum = $lang->formatNum( $number );
|
|
|
|
|
|
$normalisedNum = $lang->parseFormattedNumber( $localisedNum );
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( $number, $normalisedNum );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function parseFormattedNumberProvider() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ 'de', 377.01 ],
|
|
|
|
|
|
[ 'fa', 334 ],
|
|
|
|
|
|
[ 'fa', 382.772 ],
|
|
|
|
|
|
[ 'ar', 1844 ],
|
|
|
|
|
|
[ 'lzh', 3731 ],
|
2020-10-21 13:57:50 +00:00
|
|
|
|
[ 'zh-classical', 7432 ],
|
|
|
|
|
|
[ 'en', 1234.567 ],
|
|
|
|
|
|
[ 'en', 0.0 ],
|
|
|
|
|
|
[ 'en', -0.0 ],
|
2020-11-09 22:04:41 +00:00
|
|
|
|
[ 'en', INF ],
|
|
|
|
|
|
[ 'en', -INF ],
|
|
|
|
|
|
[ 'en', NAN ],
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2014-04-24 02:33:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-11-27 19:09:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::commafy()
|
|
|
|
|
|
* @dataProvider provideCommafyData
|
|
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testCommafy( $number, $numbersWithCommas ) {
|
2020-10-21 17:40:28 +00:00
|
|
|
|
$this->hideDeprecated( 'Language::commafy' );
|
2017-06-02 08:42:28 +00:00
|
|
|
|
$this->hideDeprecated( 'Language::formatNum with a non-numeric string' );
|
2012-11-27 19:09:04 +00:00
|
|
|
|
$this->assertEquals(
|
|
|
|
|
|
$numbersWithCommas,
|
|
|
|
|
|
$this->getLang()->commafy( $number ),
|
|
|
|
|
|
"commafy('$number')"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-22 02:12:37 +00:00
|
|
|
|
public static function provideCommafyData() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ -1, '-1' ],
|
|
|
|
|
|
[ 10, '10' ],
|
|
|
|
|
|
[ 100, '100' ],
|
|
|
|
|
|
[ 1000, '1,000' ],
|
|
|
|
|
|
[ 10000, '10,000' ],
|
|
|
|
|
|
[ 100000, '100,000' ],
|
|
|
|
|
|
[ 1000000, '1,000,000' ],
|
|
|
|
|
|
[ -1.0001, '-1.0001' ],
|
|
|
|
|
|
[ 1.0001, '1.0001' ],
|
|
|
|
|
|
[ 10.0001, '10.0001' ],
|
|
|
|
|
|
[ 100.0001, '100.0001' ],
|
|
|
|
|
|
[ 1000.0001, '1,000.0001' ],
|
|
|
|
|
|
[ 10000.0001, '10,000.0001' ],
|
|
|
|
|
|
[ 100000.0001, '100,000.0001' ],
|
|
|
|
|
|
[ 1000000.0001, '1,000,000.0001' ],
|
|
|
|
|
|
[ '200000000000000000000', '200,000,000,000,000,000,000' ],
|
|
|
|
|
|
[ '-200000000000000000000', '-200,000,000,000,000,000,000' ],
|
Language: ensure commafy does not corrupt UTF-8 strings
The commafy method "should" be given valid numeric strings, but this
wasn't enforced, and if were provided input which started with a UTF-8
multibyte character and then had a single ASCII digit somewhere after
that, it would return the first byte of the input string, resulting in
an invalid UTF-8 sequence.
Fix this bug with belt and suspenders: first, enforce the expected
input structure at the top of the function. Since there is existing
code which expects us to "do our best" with invalid input, split the
input string into valid numeric chunks before processing it. This
split code triggers a hard deprecation warning, so we can eventually
remove it.
Second, make the sign test more robust and anchor the $integerPart
regexp to match assumptions made in the algorithm, so that even if
bogus input *did* creep through (a sloppy future maintainer, say) it
wouldn't lead to corrupt UTF-8 in the output.
Add test cases covering these conditions, borrowing liberally from
I741b70757e43b1312c86719920e29885566e916c, which points out that while
commafy expects numeric strings, formatNum replaces – character by
character – digits and separator characters with language specific
ones. Optionally thousand separators are added (a.k.a. "commafy").
Eventually we should tighten the spec for formatNum as well; some of
this has already been done in
I03ffa99f7de1dcc48535ba1e1251567dbf3db116 and
I89b17a9e11b3afc6c653ba7ccc6ff84c37863b66.
Some additional test case fixes borrowed from
If45ef33a50b2623322f17306d123f0d8cb468618 which updated a few test
cases to be more specific, i.e. actually test stuff (for example,
commafy doesn't happen on 3-digit numbers, and numerals are not
translated in English).
Bug: T237467
Depends-On: I89b17a9e11b3afc6c653ba7ccc6ff84c37863b66
Depends-On: I9dcbe91fa926dba1cfd24d9bf075ee1ebef36b9e
Depends-On: I03ffa99f7de1dcc48535ba1e1251567dbf3db116
Change-Id: If3dcfd71acd8ebf3eea6a49408260f2aaa07e469
2020-09-08 23:19:41 +00:00
|
|
|
|
[ '1.', '1.' ],
|
|
|
|
|
|
[ '-.1', '-.1' ],
|
|
|
|
|
|
[ '-0', '-0' ],
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure non-numeric strings are not destroyed
|
|
|
|
|
|
// (But these will trigger deprecation warnings)
|
|
|
|
|
|
[ 'The number is 1234', 'The number is 1,234' ],
|
|
|
|
|
|
[ '1234 is the number', '1,234 is the number' ],
|
|
|
|
|
|
[ '.', '.' ],
|
|
|
|
|
|
[ ',', ',' ],
|
|
|
|
|
|
[ '-', '-' ],
|
|
|
|
|
|
[ 'abcdefg', 'abcdefg' ],
|
|
|
|
|
|
[ 'dontBeF00led.2', 'dontBeF00led.2' ],
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2012-11-27 19:09:04 +00:00
|
|
|
|
}
|
2013-01-07 09:59:16 +00:00
|
|
|
|
|
2013-10-22 10:32:29 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::listToText
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testListToText() {
|
2013-01-07 09:59:16 +00:00
|
|
|
|
$lang = $this->getLang();
|
|
|
|
|
|
$and = $lang->getMessageFromDB( 'and' );
|
|
|
|
|
|
$s = $lang->getMessageFromDB( 'word-separator' );
|
|
|
|
|
|
$c = $lang->getMessageFromDB( 'comma-separator' );
|
|
|
|
|
|
|
2019-09-17 14:28:35 +00:00
|
|
|
|
$this->assertSame( '', $lang->listToText( [] ) );
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$this->assertEquals( 'a', $lang->listToText( [ 'a' ] ) );
|
|
|
|
|
|
$this->assertEquals( "a{$and}{$s}b", $lang->listToText( [ 'a', 'b' ] ) );
|
|
|
|
|
|
$this->assertEquals( "a{$c}b{$and}{$s}c", $lang->listToText( [ 'a', 'b', 'c' ] ) );
|
|
|
|
|
|
$this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( [ 'a', 'b', 'c', 'd' ] ) );
|
2013-01-07 09:59:16 +00:00
|
|
|
|
}
|
2013-01-14 07:21:10 +00:00
|
|
|
|
|
2013-06-07 08:50:10 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideGetParentLanguage
|
2013-10-22 10:32:29 +00:00
|
|
|
|
* @covers Language::getParentLanguage
|
2013-06-07 08:50:10 +00:00
|
|
|
|
*/
|
2013-10-22 10:32:29 +00:00
|
|
|
|
public function testGetParentLanguage( $code, $expected, $comment ) {
|
2013-06-07 08:50:10 +00:00
|
|
|
|
$lang = Language::factory( $code );
|
2020-01-09 23:48:34 +00:00
|
|
|
|
if ( $expected === null ) {
|
2013-06-07 08:50:10 +00:00
|
|
|
|
$this->assertNull( $lang->getParentLanguage(), $comment );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$this->assertEquals( $expected, $lang->getParentLanguage()->getCode(), $comment );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static function provideGetParentLanguage() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [
|
|
|
|
|
|
[ 'zh-cn', 'zh', 'zh is the parent language of zh-cn' ],
|
|
|
|
|
|
[ 'zh', 'zh', 'zh is defined as the parent language of zh, '
|
|
|
|
|
|
. 'because zh converter can convert zh-cn to zh' ],
|
|
|
|
|
|
[ 'zh-invalid', null, 'do not be fooled by arbitrarily composed language codes' ],
|
2013-07-27 23:01:54 +00:00
|
|
|
|
[ 'de-formal', null, 'de does not have converter' ],
|
|
|
|
|
|
[ 'de', null, 'de does not have converter' ],
|
2021-12-05 06:43:20 +00:00
|
|
|
|
[ 'ike-cans', 'iu', 'do not simply strip out the subcode' ],
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2013-06-07 08:50:10 +00:00
|
|
|
|
}
|
2013-03-14 11:29:49 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
* Example of the real localisation files being loaded.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This might be a bit cumbersome to maintain long-term,
|
|
|
|
|
|
* but still valueable to have as integration test.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @covers Language
|
|
|
|
|
|
* @covers LocalisationCache
|
2013-03-14 11:29:49 +00:00
|
|
|
|
*/
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
public function testGetNamespaceAliasesReal() {
|
|
|
|
|
|
$language = Language::factory( 'zh' );
|
2013-03-14 11:29:49 +00:00
|
|
|
|
$aliases = $language->getNamespaceAliases();
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
$this->assertSame( NS_FILE, $aliases['文件'] );
|
|
|
|
|
|
$this->assertSame( NS_FILE, $aliases['檔案'] );
|
2013-03-14 11:29:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::getNamespaceAliases
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testGetNamespaceAliasesFullLogic() {
|
|
|
|
|
|
$langNameUtils = $this->getMockBuilder( LanguageNameUtils::class )
|
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
|
|
|
|
->setConstructorArgs( [
|
|
|
|
|
|
new ServiceOptions( LanguageNameUtils::CONSTRUCTOR_OPTIONS, [
|
|
|
|
|
|
'ExtraLanguageNames' => [],
|
|
|
|
|
|
'UsePigLatinVariant' => false,
|
|
|
|
|
|
] ),
|
|
|
|
|
|
$this->createHookContainer()
|
|
|
|
|
|
] )
|
2021-03-20 15:18:58 +00:00
|
|
|
|
->onlyMethods( [ 'getMessagesFileName' ] )
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
->getMock();
|
|
|
|
|
|
$langNameUtils->method( 'getMessagesFileName' )->will(
|
2021-02-07 13:10:36 +00:00
|
|
|
|
$this->returnCallback( static function ( $code ) {
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
return __DIR__ . '/../data/messages/Messages_' . $code . '.php';
|
|
|
|
|
|
} )
|
|
|
|
|
|
);
|
|
|
|
|
|
$this->setMwGlobals( 'wgNamespaceAliases', [
|
|
|
|
|
|
'Mouse' => NS_SPECIAL,
|
|
|
|
|
|
] );
|
|
|
|
|
|
$this->setService( 'LanguageNameUtils', $langNameUtils );
|
|
|
|
|
|
|
|
|
|
|
|
$language = MediaWikiServices::getInstance()->getLanguageFactory()->getLanguage( 'x-bar' );
|
|
|
|
|
|
|
|
|
|
|
|
$this->assertEquals(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
// from x-bar
|
|
|
|
|
|
'Cat' => NS_FILE,
|
|
|
|
|
|
'Cat_toots' => NS_FILE_TALK,
|
|
|
|
|
|
// inherited from x-foo
|
|
|
|
|
|
'Dog' => NS_USER,
|
|
|
|
|
|
'Dog' => NS_USER_TALK,
|
|
|
|
|
|
// add from site configuration
|
|
|
|
|
|
'Mouse' => NS_SPECIAL,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
],
|
languages: Move default $wgNamespaceAliases to MessagesEn.php
These are not configuration but business logic, similar to the
canonical names that are in NamespaceInfo.php, these must always
exist and cannot be altered or unset.
They were previously unconditionally assigned during all requests
in Setup.php and passed down as "site configuration".
Changes:
* Move them to MessagesEn.php where they can be cached and
processed the same way as other core-provided aliases.
Document and confirm with tests that this is a mergeable
attribute that follows the language chain.
* Remove the duplicated code in a few places that was reading
this variable + Language::getNamespaceAliases(), to instead
just call the latter and move the logic there, centralised,
and tested.
In doing so I noticed that these were applied in an
inconsistent order. Sometimes the config won, sometimes not.
There's no obvious right or wrong way here, but I've chosen
to standardise on the way that Language::getNamespaceIds() did
it, which is that config wins. This because that method seems
to be most widely used of the three (it decides how URLs and
titles are parsed), and thus the one I least want to change
the behaviour of.
* Document that $wgNamespaceAliases may only be used to
define (extra) aliases, it is and never was a way to access
the complete list of aliases.
Bug: T189966
Change-Id: Ibb14181aba8c1b509264ed40523e9ab4000fd71a
2020-03-14 18:16:20 +00:00
|
|
|
|
$language->getNamespaceAliases()
|
|
|
|
|
|
);
|
2013-03-14 11:29:49 +00:00
|
|
|
|
}
|
2016-05-23 14:45:06 +00:00
|
|
|
|
|
2018-10-19 19:00:52 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::hasVariant
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testHasVariant() {
|
|
|
|
|
|
// See LanguageSrTest::testHasVariant() for additional tests
|
|
|
|
|
|
$en = Language::factory( 'en' );
|
|
|
|
|
|
$this->assertTrue( $en->hasVariant( 'en' ), 'base is always a variant' );
|
|
|
|
|
|
$this->assertFalse( $en->hasVariant( 'en-bogus' ), 'bogus en variant' );
|
|
|
|
|
|
|
|
|
|
|
|
$bogus = Language::factory( 'bogus' );
|
|
|
|
|
|
$this->assertTrue( $bogus->hasVariant( 'bogus' ), 'base is always a variant' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-28 08:24:40 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::equals
|
|
|
|
|
|
*/
|
2016-05-23 14:45:06 +00:00
|
|
|
|
public function testEquals() {
|
2018-07-07 09:53:04 +00:00
|
|
|
|
$en1 = Language::factory( 'en' );
|
2016-05-23 14:45:06 +00:00
|
|
|
|
$en2 = Language::factory( 'en' );
|
2018-08-07 13:17:16 +00:00
|
|
|
|
$en3 = $this->newLanguage();
|
2018-07-07 09:53:04 +00:00
|
|
|
|
$this->assertTrue( $en1->equals( $en2 ), 'en1 equals en2' );
|
|
|
|
|
|
$this->assertTrue( $en2->equals( $en3 ), 'en2 equals en3' );
|
|
|
|
|
|
$this->assertTrue( $en3->equals( $en1 ), 'en3 equals en1' );
|
2016-05-23 14:45:06 +00:00
|
|
|
|
|
|
|
|
|
|
$fr = Language::factory( 'fr' );
|
|
|
|
|
|
$this->assertFalse( $en1->equals( $fr ), 'en not equals fr' );
|
2018-07-07 09:53:04 +00:00
|
|
|
|
|
|
|
|
|
|
$ar1 = Language::factory( 'ar' );
|
2018-08-07 13:17:16 +00:00
|
|
|
|
$ar2 = $this->newLanguage( LanguageAr::class, 'ar' );
|
2018-07-07 09:53:04 +00:00
|
|
|
|
$this->assertTrue( $ar1->equals( $ar2 ), 'ar equals ar' );
|
2016-05-23 14:45:06 +00:00
|
|
|
|
}
|
2019-04-09 17:02:03 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @dataProvider provideUcfirst
|
|
|
|
|
|
* @covers Language::ucfirst
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testUcfirst( $orig, $expected, $desc, $overrides = false ) {
|
2018-08-07 13:17:16 +00:00
|
|
|
|
$lang = $this->newLanguage();
|
2019-04-09 17:02:03 +00:00
|
|
|
|
if ( is_array( $overrides ) ) {
|
|
|
|
|
|
$this->setMwGlobals( [ 'wgOverrideUcfirstCharacters' => $overrides ] );
|
|
|
|
|
|
}
|
2022-02-08 05:12:43 +00:00
|
|
|
|
$this->assertSame( $expected, $lang->ucfirst( $orig ), $desc );
|
2019-04-09 17:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static function provideUcfirst() {
|
|
|
|
|
|
return [
|
|
|
|
|
|
[ 'alice', 'Alice', 'simple ASCII string', false ],
|
|
|
|
|
|
[ 'århus', 'Århus', 'unicode string', false ],
|
2020-05-10 00:09:19 +00:00
|
|
|
|
// overrides do not affect ASCII characters
|
2019-04-09 17:02:03 +00:00
|
|
|
|
[ 'foo', 'Foo', 'ASCII is not overriden', [ 'f' => 'b' ] ],
|
|
|
|
|
|
// but they do affect non-ascii ones
|
|
|
|
|
|
[ 'èl', 'Ll' , 'Non-ASCII is overridden', [ 'è' => 'L' ] ],
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
2019-05-02 14:23:42 +00:00
|
|
|
|
|
|
|
|
|
|
// The following methods are for LanguageNameUtilsTestTrait
|
|
|
|
|
|
|
|
|
|
|
|
private function isSupportedLanguage( $code ) {
|
|
|
|
|
|
return Language::isSupportedLanguage( $code );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function isValidCode( $code ) {
|
|
|
|
|
|
return Language::isValidCode( $code );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function isValidBuiltInCode( $code ) {
|
|
|
|
|
|
return Language::isValidBuiltInCode( $code );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function isKnownLanguageTag( $code ) {
|
|
|
|
|
|
return Language::isKnownLanguageTag( $code );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-11-04 19:00:40 +00:00
|
|
|
|
protected function setLanguageTemporaryHook( string $hookName, $handler ): void {
|
|
|
|
|
|
$this->setTemporaryHook( $hookName, $handler );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-02 14:23:42 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Call getLanguageName() and getLanguageNames() using the Language static methods.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param array $options To set globals for testing Language
|
|
|
|
|
|
* @param string $expected
|
|
|
|
|
|
* @param string $code
|
|
|
|
|
|
* @param mixed ...$otherArgs Optionally, pass $inLanguage and/or $include.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function assertGetLanguageNames( array $options, $expected, $code, ...$otherArgs ) {
|
|
|
|
|
|
if ( $options ) {
|
|
|
|
|
|
foreach ( $options as $key => $val ) {
|
|
|
|
|
|
$this->setMwGlobals( "wg$key", $val );
|
|
|
|
|
|
}
|
|
|
|
|
|
$this->resetServices();
|
|
|
|
|
|
}
|
|
|
|
|
|
$this->assertSame( $expected,
|
|
|
|
|
|
Language::fetchLanguageNames( ...$otherArgs )[strtolower( $code )] ?? '' );
|
|
|
|
|
|
$this->assertSame( $expected, Language::fetchLanguageName( $code, ...$otherArgs ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function getLanguageNames( ...$args ) {
|
|
|
|
|
|
return Language::fetchLanguageNames( ...$args );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function getLanguageName( ...$args ) {
|
|
|
|
|
|
return Language::fetchLanguageName( ...$args );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-30 21:36:43 +00:00
|
|
|
|
private function getFileName( ...$args ) {
|
2019-05-02 14:23:42 +00:00
|
|
|
|
return Language::getFileName( ...$args );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-30 21:36:43 +00:00
|
|
|
|
private function getMessagesFileName( $code ) {
|
2019-05-02 14:23:42 +00:00
|
|
|
|
return Language::getMessagesFileName( $code );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-30 21:36:43 +00:00
|
|
|
|
private function getJsonMessagesFileName( $code ) {
|
2019-05-02 14:23:42 +00:00
|
|
|
|
return Language::getJsonMessagesFileName( $code );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @todo This really belongs in the cldr extension's tests.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @covers MediaWiki\Languages\LanguageNameUtils::isKnownLanguageTag
|
|
|
|
|
|
* @covers Language::isKnownLanguageTag
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testIsKnownLanguageTag_cldr() {
|
2021-04-08 19:17:42 +00:00
|
|
|
|
if ( !class_exists( LanguageNames::class ) ) {
|
2019-05-02 14:23:42 +00:00
|
|
|
|
$this->markTestSkipped( 'The LanguageNames class is not available. '
|
|
|
|
|
|
. 'The CLDR extension is probably not installed.' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// We need to restore the extension's hook that we removed.
|
|
|
|
|
|
$this->setMwGlobals( 'wgHooks', $this->origHooks );
|
|
|
|
|
|
|
|
|
|
|
|
// "pal" is an ancient language, which probably will not appear in Names.php, but appears in
|
|
|
|
|
|
// CLDR in English
|
|
|
|
|
|
$this->assertTrue( Language::isKnownLanguageTag( 'pal' ) );
|
|
|
|
|
|
}
|
2019-11-17 09:52:02 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::getNamespaces
|
|
|
|
|
|
* @covers Language::fixVariableInNamespace
|
|
|
|
|
|
* @dataProvider provideGetNamespaces
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testGetNamespaces( string $langCode, array $config, array $expected ) {
|
|
|
|
|
|
$langClass = Language::class . ucfirst( $langCode );
|
|
|
|
|
|
if ( !class_exists( $langClass ) ) {
|
|
|
|
|
|
$langClass = Language::class;
|
|
|
|
|
|
}
|
|
|
|
|
|
/** @var Language $lang */
|
|
|
|
|
|
$lang = new $langClass(
|
|
|
|
|
|
$langCode,
|
|
|
|
|
|
MediaWikiServices::getInstance()->getLocalisationCache(),
|
|
|
|
|
|
$this->createNoOpMock( LanguageNameUtils::class ),
|
|
|
|
|
|
$this->createNoOpMock( LanguageFallback::class ),
|
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
|
|
|
|
$this->createNoOpMock( LanguageConverterFactory::class ),
|
2020-11-04 19:00:40 +00:00
|
|
|
|
$this->createMock( HookContainer::class )
|
2019-11-17 09:52:02 +00:00
|
|
|
|
);
|
|
|
|
|
|
$config += [
|
|
|
|
|
|
'wgMetaNamespace' => 'Project',
|
|
|
|
|
|
'wgMetaNamespaceTalk' => false,
|
|
|
|
|
|
'wgExtraNamespaces' => [],
|
|
|
|
|
|
];
|
|
|
|
|
|
$this->setMwGlobals( $config );
|
|
|
|
|
|
$namespaces = $lang->getNamespaces();
|
2021-12-06 09:02:18 +00:00
|
|
|
|
$this->assertArraySubmapSame( $expected, $namespaces );
|
2019-11-17 09:52:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function provideGetNamespaces() {
|
|
|
|
|
|
$enNamespaces = [
|
|
|
|
|
|
NS_MEDIA => 'Media',
|
|
|
|
|
|
NS_SPECIAL => 'Special',
|
|
|
|
|
|
NS_MAIN => '',
|
|
|
|
|
|
NS_TALK => 'Talk',
|
|
|
|
|
|
NS_USER => 'User',
|
|
|
|
|
|
NS_USER_TALK => 'User_talk',
|
|
|
|
|
|
NS_FILE => 'File',
|
|
|
|
|
|
NS_FILE_TALK => 'File_talk',
|
|
|
|
|
|
NS_MEDIAWIKI => 'MediaWiki',
|
|
|
|
|
|
NS_MEDIAWIKI_TALK => 'MediaWiki_talk',
|
|
|
|
|
|
NS_TEMPLATE => 'Template',
|
|
|
|
|
|
NS_TEMPLATE_TALK => 'Template_talk',
|
|
|
|
|
|
NS_HELP => 'Help',
|
|
|
|
|
|
NS_HELP_TALK => 'Help_talk',
|
|
|
|
|
|
NS_CATEGORY => 'Category',
|
|
|
|
|
|
NS_CATEGORY_TALK => 'Category_talk',
|
|
|
|
|
|
];
|
|
|
|
|
|
$ukNamespaces = [
|
|
|
|
|
|
NS_MEDIA => 'Медіа',
|
|
|
|
|
|
NS_SPECIAL => 'Спеціальна',
|
|
|
|
|
|
NS_TALK => 'Обговорення',
|
|
|
|
|
|
NS_USER => 'Користувач',
|
|
|
|
|
|
NS_USER_TALK => 'Обговорення_користувача',
|
|
|
|
|
|
NS_FILE => 'Файл',
|
|
|
|
|
|
NS_FILE_TALK => 'Обговорення_файлу',
|
|
|
|
|
|
NS_MEDIAWIKI => 'MediaWiki',
|
|
|
|
|
|
NS_MEDIAWIKI_TALK => 'Обговорення_MediaWiki',
|
|
|
|
|
|
NS_TEMPLATE => 'Шаблон',
|
|
|
|
|
|
NS_TEMPLATE_TALK => 'Обговорення_шаблону',
|
|
|
|
|
|
NS_HELP => 'Довідка',
|
|
|
|
|
|
NS_HELP_TALK => 'Обговорення_довідки',
|
|
|
|
|
|
NS_CATEGORY => 'Категорія',
|
|
|
|
|
|
NS_CATEGORY_TALK => 'Обговорення_категорії',
|
|
|
|
|
|
];
|
|
|
|
|
|
return [
|
|
|
|
|
|
'Default configuration' => [
|
|
|
|
|
|
'en',
|
|
|
|
|
|
[],
|
|
|
|
|
|
$enNamespaces + [
|
|
|
|
|
|
NS_PROJECT => 'Project',
|
|
|
|
|
|
NS_PROJECT_TALK => 'Project_talk',
|
|
|
|
|
|
],
|
|
|
|
|
|
],
|
|
|
|
|
|
'Custom project NS + extra' => [
|
|
|
|
|
|
'en',
|
|
|
|
|
|
[
|
|
|
|
|
|
'wgMetaNamespace' => 'Wikipedia',
|
|
|
|
|
|
'wgExtraNamespaces' => [
|
|
|
|
|
|
100 => 'Borderlands',
|
|
|
|
|
|
101 => 'Borderlands_talk',
|
|
|
|
|
|
],
|
|
|
|
|
|
],
|
|
|
|
|
|
$enNamespaces + [
|
|
|
|
|
|
NS_PROJECT => 'Wikipedia',
|
|
|
|
|
|
NS_PROJECT_TALK => 'Wikipedia_talk',
|
|
|
|
|
|
100 => 'Borderlands',
|
|
|
|
|
|
101 => 'Borderlands_talk',
|
|
|
|
|
|
],
|
|
|
|
|
|
],
|
|
|
|
|
|
'Custom project NS and talk + extra' => [
|
|
|
|
|
|
'en',
|
|
|
|
|
|
[
|
|
|
|
|
|
'wgMetaNamespace' => 'Wikipedia',
|
|
|
|
|
|
'wgMetaNamespaceTalk' => 'Wikipedia_drama',
|
|
|
|
|
|
'wgExtraNamespaces' => [
|
|
|
|
|
|
100 => 'Borderlands',
|
|
|
|
|
|
101 => 'Borderlands_talk',
|
|
|
|
|
|
],
|
|
|
|
|
|
],
|
|
|
|
|
|
$enNamespaces + [
|
|
|
|
|
|
NS_PROJECT => 'Wikipedia',
|
|
|
|
|
|
NS_PROJECT_TALK => 'Wikipedia_drama',
|
|
|
|
|
|
100 => 'Borderlands',
|
|
|
|
|
|
101 => 'Borderlands_talk',
|
|
|
|
|
|
],
|
|
|
|
|
|
],
|
|
|
|
|
|
'Ukrainian default' => [
|
|
|
|
|
|
'uk',
|
|
|
|
|
|
[],
|
|
|
|
|
|
$ukNamespaces + [
|
|
|
|
|
|
NS_MAIN => '',
|
|
|
|
|
|
NS_PROJECT => 'Project',
|
|
|
|
|
|
NS_PROJECT_TALK => 'Обговорення_Project',
|
|
|
|
|
|
],
|
|
|
|
|
|
],
|
|
|
|
|
|
'Ukrainian custom NS' => [
|
|
|
|
|
|
'uk',
|
|
|
|
|
|
[
|
|
|
|
|
|
'wgMetaNamespace' => 'Вікіпедія',
|
|
|
|
|
|
],
|
|
|
|
|
|
$ukNamespaces + [
|
|
|
|
|
|
NS_MAIN => '',
|
|
|
|
|
|
NS_PROJECT => 'Вікіпедія',
|
|
|
|
|
|
NS_PROJECT_TALK => 'Обговорення_Вікіпедії',
|
|
|
|
|
|
],
|
|
|
|
|
|
],
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
2021-10-13 18:22:26 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::getGroupName
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testGetGroupName() {
|
|
|
|
|
|
$lang = $this->getLang();
|
|
|
|
|
|
$groupName = $lang->getGroupName( 'bot' );
|
|
|
|
|
|
$this->assertSame( 'Bots', $groupName );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-10-15 17:39:56 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::getGroupMemberName
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testGetGroupMemberName() {
|
|
|
|
|
|
$lang = $this->getLang();
|
|
|
|
|
|
$user = new UserIdentityValue( 1, 'user' );
|
|
|
|
|
|
$groupMemberName = $lang->getGroupMemberName( 'bot', $user );
|
|
|
|
|
|
$this->assertSame( 'bot', $groupMemberName );
|
|
|
|
|
|
|
|
|
|
|
|
$lang = $this->getServiceContainer()->getLanguageFactory()->getLanguage( 'qqx' );
|
|
|
|
|
|
$groupMemberName = $lang->getGroupMemberName( 'bot', $user );
|
|
|
|
|
|
$this->assertSame( '(group-bot-member: user)', $groupMemberName );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @covers Language::msg
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function testMsg() {
|
|
|
|
|
|
$lang = TestingAccessWrapper::newFromObject( $this->getLang() );
|
2021-12-26 11:56:22 +00:00
|
|
|
|
$this->assertSame( 'Line 1:', $lang->msg( 'lineno', '1' )->text() );
|
2021-10-15 17:39:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-12-14 16:26:35 +00:00
|
|
|
|
}
|