wiki.techinc.nl/tests/phpunit/unit/includes/SiteConfigurationTest.php
Aryeh Gregor 7b4b0135b9 Use str_starts_with/str_ends_with
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
2022-05-02 10:59:58 +03:00

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'
);
}
}