All the other ways of doing it were ridiculous and much harder to read, and usually required repeating the needle expression (to get its length). I found these occurrences by grepping for various expressions, but I undoubtedly missed some. I didn't try replacing the many instances of strpos(...) === 0 with str_starts_with(...), because I think they're readable enough as-is (although less efficient). Likewise I didn't try porting strpos(...) !== false to str_contains(...). For case-insensitive comparisons, Tim Starling requested that we stick with substr_compare() because it's more efficient than calling strtolower(). On PHP < 8 these functions will be included with a polyfill via vendor/autoload.php. This is included at the beginning of includes/AutoLoader.php, so if our autoloader has been included the polyfill will be available. This means it should be safe to call these functions from any code that would not be usable without our autoloader. Three uses that Tim Starling identified as being performance-sensitive have been split out to a separate commit for porting after the switch to PHP 8. Change-Id: I113a8d052b6845852c15969a2f0e6fbbe3e9f8d9
437 lines
11 KiB
PHP
437 lines
11 KiB
PHP
<?php
|
|
|
|
class SiteConfigurationTest extends \MediaWikiUnitTestCase {
|
|
|
|
/**
|
|
* @var SiteConfiguration
|
|
*/
|
|
protected $mConf;
|
|
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
|
|
$this->mConf = new SiteConfiguration;
|
|
|
|
$this->mConf->suffixes = [ 'wikipedia' => 'wiki' ];
|
|
$this->mConf->wikis = [ 'enwiki', 'dewiki', 'frwiki' ];
|
|
$this->mConf->settings = [
|
|
'SimpleKey' => [
|
|
'wiki' => 'wiki',
|
|
'tag' => 'tag',
|
|
'enwiki' => 'enwiki',
|
|
'dewiki' => 'dewiki',
|
|
'frwiki' => 'frwiki',
|
|
],
|
|
|
|
'Fallback' => [
|
|
'default' => 'default',
|
|
'wiki' => 'wiki',
|
|
'tag' => 'tag',
|
|
'frwiki' => 'frwiki',
|
|
'null_wiki' => null,
|
|
],
|
|
|
|
'WithParams' => [
|
|
'default' => '$lang $site $wiki',
|
|
],
|
|
|
|
'WithNestedParams' => [
|
|
'default' => [
|
|
'monday' => 'Moon $lang $site',
|
|
'saturday' => 'Saturn $lang $site',
|
|
],
|
|
'+dewiki' => [
|
|
'Sonntag' => 'Sonne $lang $site',
|
|
],
|
|
],
|
|
|
|
'+SomeGlobal' => [
|
|
'wiki' => [
|
|
'wiki' => 'wiki',
|
|
],
|
|
'tag' => [
|
|
'tag' => 'tag',
|
|
],
|
|
'enwiki' => [
|
|
'enwiki' => 'enwiki',
|
|
],
|
|
'dewiki' => [
|
|
'dewiki' => 'dewiki',
|
|
],
|
|
'frwiki' => [
|
|
'frwiki' => 'frwiki',
|
|
],
|
|
],
|
|
|
|
'MergeIt' => [
|
|
'+wiki' => [
|
|
'wiki' => 'wiki',
|
|
],
|
|
'+tag' => [
|
|
'tag' => 'tag',
|
|
],
|
|
'default' => [
|
|
'default' => 'default',
|
|
],
|
|
'+enwiki' => [
|
|
'enwiki' => 'enwiki',
|
|
],
|
|
'+dewiki' => [
|
|
'dewiki' => 'dewiki',
|
|
],
|
|
'+frwiki' => [
|
|
'frwiki' => 'frwiki',
|
|
],
|
|
],
|
|
];
|
|
|
|
$GLOBALS['SomeGlobal'] = [ 'SomeGlobal' => 'SomeGlobal' ];
|
|
}
|
|
|
|
/**
|
|
* This function is used as a callback within the tests below
|
|
* @param SiteConfiguration $conf
|
|
* @param string $wiki
|
|
* @return array
|
|
*/
|
|
public static function getSiteParamsCallback( $conf, $wiki ) {
|
|
$site = null;
|
|
$lang = null;
|
|
foreach ( $conf->suffixes as $suffix ) {
|
|
if ( str_ends_with( $wiki, $suffix ) ) {
|
|
$site = $suffix;
|
|
$lang = substr( $wiki, 0, -strlen( $suffix ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return [
|
|
'suffix' => $site,
|
|
'lang' => $lang,
|
|
'params' => [
|
|
'lang' => $lang,
|
|
'site' => $site,
|
|
'wiki' => $wiki,
|
|
],
|
|
'tags' => [ 'tag' ],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @covers SiteConfiguration::siteFromDB
|
|
*/
|
|
public function testSiteFromDb() {
|
|
$this->assertSame(
|
|
[ 'wikipedia', 'en' ],
|
|
$this->mConf->siteFromDB( 'enwiki' ),
|
|
'siteFromDB()'
|
|
);
|
|
$this->assertSame(
|
|
[ 'wikipedia', '' ],
|
|
$this->mConf->siteFromDB( 'wiki' ),
|
|
'siteFromDB() on a suffix'
|
|
);
|
|
$this->assertSame(
|
|
[ null, null ],
|
|
$this->mConf->siteFromDB( 'wikien' ),
|
|
'siteFromDB() on a non-existing wiki'
|
|
);
|
|
|
|
$this->mConf->suffixes = [ 'wiki', '' ];
|
|
$this->assertSame(
|
|
[ '', 'wikien' ],
|
|
$this->mConf->siteFromDB( 'wikien' ),
|
|
'siteFromDB() on a non-existing wiki (2)'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers SiteConfiguration::getLocalDatabases
|
|
*/
|
|
public function testGetLocalDatabases() {
|
|
$this->assertEquals(
|
|
[ 'enwiki', 'dewiki', 'frwiki' ],
|
|
$this->mConf->getLocalDatabases(),
|
|
'getLocalDatabases()'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers SiteConfiguration::get
|
|
*/
|
|
public function testGetConfVariables() {
|
|
// Simple
|
|
$this->assertEquals(
|
|
'enwiki',
|
|
$this->mConf->get( 'SimpleKey', 'enwiki', 'wiki' ),
|
|
'get(): simple setting on an existing wiki'
|
|
);
|
|
$this->assertEquals(
|
|
'dewiki',
|
|
$this->mConf->get( 'SimpleKey', 'dewiki', 'wiki' ),
|
|
'get(): simple setting on an existing wiki (2)'
|
|
);
|
|
$this->assertEquals(
|
|
'frwiki',
|
|
$this->mConf->get( 'SimpleKey', 'frwiki', 'wiki' ),
|
|
'get(): simple setting on an existing wiki (3)'
|
|
);
|
|
$this->assertEquals(
|
|
'wiki',
|
|
$this->mConf->get( 'SimpleKey', 'wiki', 'wiki' ),
|
|
'get(): simple setting on an suffix'
|
|
);
|
|
$this->assertEquals(
|
|
'wiki',
|
|
$this->mConf->get( 'SimpleKey', 'eswiki', 'wiki' ),
|
|
'get(): simple setting on a non-existing wiki'
|
|
);
|
|
|
|
// Fallback
|
|
$this->assertEquals(
|
|
'wiki',
|
|
$this->mConf->get( 'Fallback', 'enwiki', 'wiki' ),
|
|
'get(): fallback setting on an existing wiki'
|
|
);
|
|
$this->assertEquals(
|
|
'tag',
|
|
$this->mConf->get( 'Fallback', 'dewiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): fallback setting on an existing wiki (with wiki tag)'
|
|
);
|
|
$this->assertEquals(
|
|
'frwiki',
|
|
$this->mConf->get( 'Fallback', 'frwiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): no fallback if wiki has its own setting (matching tag)'
|
|
);
|
|
$this->assertSame(
|
|
// Potential regression test for T192855
|
|
null,
|
|
$this->mConf->get( 'Fallback', 'null_wiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): no fallback if wiki has its own setting (matching tag and uses null)'
|
|
);
|
|
$this->assertEquals(
|
|
'wiki',
|
|
$this->mConf->get( 'Fallback', 'wiki', 'wiki' ),
|
|
'get(): fallback setting on an suffix'
|
|
);
|
|
$this->assertEquals(
|
|
'wiki',
|
|
$this->mConf->get( 'Fallback', 'wiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): fallback setting on an suffix (with wiki tag)'
|
|
);
|
|
$this->assertEquals(
|
|
'wiki',
|
|
$this->mConf->get( 'Fallback', 'eswiki', 'wiki' ),
|
|
'get(): fallback setting on a non-existing wiki'
|
|
);
|
|
$this->assertEquals(
|
|
'tag',
|
|
$this->mConf->get( 'Fallback', 'eswiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): fallback setting on a non-existing wiki (with wiki tag)'
|
|
);
|
|
|
|
// Merging
|
|
$common = [ 'wiki' => 'wiki', 'default' => 'default' ];
|
|
$commonTag = [ 'tag' => 'tag', 'wiki' => 'wiki', 'default' => 'default' ];
|
|
$this->assertEquals(
|
|
[ 'enwiki' => 'enwiki' ] + $common,
|
|
$this->mConf->get( 'MergeIt', 'enwiki', 'wiki' ),
|
|
'get(): merging setting on an existing wiki'
|
|
);
|
|
$this->assertEquals(
|
|
[ 'enwiki' => 'enwiki' ] + $commonTag,
|
|
$this->mConf->get( 'MergeIt', 'enwiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): merging setting on an existing wiki (with tag)'
|
|
);
|
|
$this->assertEquals(
|
|
[ 'dewiki' => 'dewiki' ] + $common,
|
|
$this->mConf->get( 'MergeIt', 'dewiki', 'wiki' ),
|
|
'get(): merging setting on an existing wiki (2)'
|
|
);
|
|
$this->assertEquals(
|
|
[ 'dewiki' => 'dewiki' ] + $commonTag,
|
|
$this->mConf->get( 'MergeIt', 'dewiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): merging setting on an existing wiki (2) (with tag)'
|
|
);
|
|
$this->assertEquals(
|
|
[ 'frwiki' => 'frwiki' ] + $common,
|
|
$this->mConf->get( 'MergeIt', 'frwiki', 'wiki' ),
|
|
'get(): merging setting on an existing wiki (3)'
|
|
);
|
|
$this->assertEquals(
|
|
[ 'frwiki' => 'frwiki' ] + $commonTag,
|
|
$this->mConf->get( 'MergeIt', 'frwiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): merging setting on an existing wiki (3) (with tag)'
|
|
);
|
|
$this->assertEquals(
|
|
[ 'wiki' => 'wiki' ] + $common,
|
|
$this->mConf->get( 'MergeIt', 'wiki', 'wiki' ),
|
|
'get(): merging setting on an suffix'
|
|
);
|
|
$this->assertEquals(
|
|
[ 'wiki' => 'wiki' ] + $commonTag,
|
|
$this->mConf->get( 'MergeIt', 'wiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): merging setting on an suffix (with tag)'
|
|
);
|
|
$this->assertEquals(
|
|
$common,
|
|
$this->mConf->get( 'MergeIt', 'eswiki', 'wiki' ),
|
|
'get(): merging setting on a non-existing wiki'
|
|
);
|
|
$this->assertEquals(
|
|
$commonTag,
|
|
$this->mConf->get( 'MergeIt', 'eswiki', 'wiki', [], [ 'tag' ] ),
|
|
'get(): merging setting on a non-existing wiki (with tag)'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers SiteConfiguration::siteFromDB
|
|
*/
|
|
public function testSiteFromDbWithCallback() {
|
|
$this->mConf->siteParamsCallback = [ __CLASS__, 'getSiteParamsCallback' ];
|
|
|
|
$this->assertSame(
|
|
[ 'wiki', 'en' ],
|
|
$this->mConf->siteFromDB( 'enwiki' ),
|
|
'siteFromDB() with callback'
|
|
);
|
|
$this->assertSame(
|
|
[ 'wiki', '' ],
|
|
$this->mConf->siteFromDB( 'wiki' ),
|
|
'siteFromDB() with callback on a suffix'
|
|
);
|
|
$this->assertSame(
|
|
[ null, null ],
|
|
$this->mConf->siteFromDB( 'wikien' ),
|
|
'siteFromDB() with callback on a non-existing wiki'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers SiteConfiguration
|
|
*/
|
|
public function testParameterReplacement() {
|
|
$this->mConf->siteParamsCallback = [ __CLASS__, 'getSiteParamsCallback' ];
|
|
|
|
$this->assertEquals(
|
|
'en wiki enwiki',
|
|
$this->mConf->get( 'WithParams', 'enwiki', 'wiki' ),
|
|
'get(): parameter replacement on an existing wiki'
|
|
);
|
|
$this->assertEquals(
|
|
'de wiki dewiki',
|
|
$this->mConf->get( 'WithParams', 'dewiki', 'wiki' ),
|
|
'get(): parameter replacement on an existing wiki (2)'
|
|
);
|
|
$this->assertEquals(
|
|
'fr wiki frwiki',
|
|
$this->mConf->get( 'WithParams', 'frwiki', 'wiki' ),
|
|
'get(): parameter replacement on an existing wiki (3)'
|
|
);
|
|
$this->assertEquals(
|
|
' wiki wiki',
|
|
$this->mConf->get( 'WithParams', 'wiki', 'wiki' ),
|
|
'get(): parameter replacement on an suffix'
|
|
);
|
|
$this->assertEquals(
|
|
'es wiki eswiki',
|
|
$this->mConf->get( 'WithParams', 'eswiki', 'wiki' ),
|
|
'get(): parameter replacement on a non-existing wiki'
|
|
);
|
|
|
|
$this->assertEquals(
|
|
[
|
|
'monday' => 'Moon en wiki',
|
|
'saturday' => 'Saturn en wiki',
|
|
],
|
|
$this->mConf->get( 'WithNestedParams', 'enwiki', 'wiki' ),
|
|
'get(): nested parameter replacement using default'
|
|
);
|
|
$this->assertEquals(
|
|
[
|
|
'monday' => 'Moon de wiki',
|
|
'saturday' => 'Saturn de wiki',
|
|
'Sonntag' => 'Sonne de wiki',
|
|
],
|
|
$this->mConf->get( 'WithNestedParams', 'dewiki', 'wiki' ),
|
|
'get(): nested parameter replacement using merged override'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers SiteConfiguration::getAll
|
|
*/
|
|
public function testGetAllGlobals() {
|
|
$this->mConf->siteParamsCallback = [ __CLASS__, 'getSiteParamsCallback' ];
|
|
|
|
$getall = [
|
|
'SimpleKey' => 'enwiki',
|
|
'Fallback' => 'tag',
|
|
'WithParams' => 'en wiki enwiki',
|
|
'WithNestedParams' => [
|
|
'monday' => 'Moon en wiki',
|
|
'saturday' => 'Saturn en wiki',
|
|
],
|
|
'SomeGlobal' => [ 'enwiki' => 'enwiki' ] + $GLOBALS['SomeGlobal'],
|
|
'MergeIt' => [
|
|
'enwiki' => 'enwiki',
|
|
'tag' => 'tag',
|
|
'wiki' => 'wiki',
|
|
'default' => 'default'
|
|
],
|
|
];
|
|
$this->assertEquals( $getall, $this->mConf->getAll( 'enwiki' ), 'getAll()' );
|
|
|
|
$this->mConf->extractAllGlobals( 'enwiki', 'wiki' );
|
|
|
|
$this->assertEquals(
|
|
$getall['SimpleKey'],
|
|
$GLOBALS['SimpleKey'],
|
|
'extractAllGlobals(): simple setting'
|
|
);
|
|
$this->assertEquals(
|
|
$getall['Fallback'],
|
|
$GLOBALS['Fallback'],
|
|
'extractAllGlobals(): fallback setting'
|
|
);
|
|
$this->assertEquals(
|
|
$getall['WithParams'],
|
|
$GLOBALS['WithParams'],
|
|
'extractAllGlobals(): parameter replacement'
|
|
);
|
|
$this->assertEquals(
|
|
$getall['SomeGlobal'],
|
|
$GLOBALS['SomeGlobal'],
|
|
'extractAllGlobals(): merging with global'
|
|
);
|
|
$this->assertEquals(
|
|
$getall['MergeIt'],
|
|
$GLOBALS['MergeIt'],
|
|
'extractAllGlobals(): merging setting'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers SiteConfiguration
|
|
*/
|
|
public function testSuffixAndTagConflict() {
|
|
$conf = new SiteConfiguration;
|
|
|
|
$conf->suffixes = [ 'foo', 'bar', 'baz' ];
|
|
$conf->wikis = [ 'aabar', 'bbbar', 'ccbar' ];
|
|
$conf->settings = [
|
|
'MyVariable' => [
|
|
'default' => [ 'x' ],
|
|
'+bar' => [ 'y' ],
|
|
],
|
|
];
|
|
|
|
// Regression test for T246858
|
|
$this->assertSame(
|
|
[ 'y', 'x' ],
|
|
$conf->get( 'MyVariable', 'bbbar', 'bar', [], [ 'alpha', 'bar' ] ),
|
|
'get(): variable with +merge for a tag that is also a suffix'
|
|
);
|
|
}
|
|
}
|