While MediaWiki Core already sets requirements for PHP versions, it should be possible for extensions to tighten these requirements. This mirrors the PHP parameter of extension infoboxes as well. This change introduces a new 'platform' key (in addition to 'MediaWiki', 'skins' and 'extensions', where non-MediaWiki software requirements will be listed in the future, starting with a PHP version constraint. Further keys are supposed to be added to allow setting constraints against php extensions and other abilities of the platform. Bug: T197535 Change-Id: I6744cc0be2363b603331af9dc860eb8603a1a89a
745 lines
19 KiB
PHP
745 lines
19 KiB
PHP
<?php
|
|
|
|
use Wikimedia\TestingAccessWrapper;
|
|
|
|
/**
|
|
* @covers ExtensionProcessor
|
|
*/
|
|
class ExtensionProcessorTest extends MediaWikiTestCase {
|
|
|
|
private $dir, $dirname;
|
|
|
|
public function setUp() {
|
|
parent::setUp();
|
|
$this->dir = __DIR__ . '/FooBar/extension.json';
|
|
$this->dirname = dirname( $this->dir );
|
|
}
|
|
|
|
/**
|
|
* 'name' is absolutely required
|
|
*
|
|
* @var array
|
|
*/
|
|
public static $default = [
|
|
'name' => 'FooBar',
|
|
];
|
|
|
|
public function testExtractInfo() {
|
|
// Test that attributes that begin with @ are ignored
|
|
$processor = new ExtensionProcessor();
|
|
$processor->extractInfo( $this->dir, self::$default + [
|
|
'@metadata' => [ 'foobarbaz' ],
|
|
'AnAttribute' => [ 'omg' ],
|
|
'AutoloadClasses' => [ 'FooBar' => 'includes/FooBar.php' ],
|
|
'SpecialPages' => [ 'Foo' => 'SpecialFoo' ],
|
|
'callback' => 'FooBar::onRegistration',
|
|
], 1 );
|
|
|
|
$extracted = $processor->getExtractedInfo();
|
|
$attributes = $extracted['attributes'];
|
|
$this->assertArrayHasKey( 'AnAttribute', $attributes );
|
|
$this->assertArrayNotHasKey( '@metadata', $attributes );
|
|
$this->assertArrayNotHasKey( 'AutoloadClasses', $attributes );
|
|
$this->assertSame(
|
|
[ 'FooBar' => 'FooBar::onRegistration' ],
|
|
$extracted['callbacks']
|
|
);
|
|
$this->assertSame(
|
|
[ 'Foo' => 'SpecialFoo' ],
|
|
$extracted['globals']['wgSpecialPages']
|
|
);
|
|
}
|
|
|
|
public function testExtractNamespaces() {
|
|
// Test that namespace IDs can be overwritten
|
|
if ( !defined( 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X' ) ) {
|
|
define( 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X', 123456 );
|
|
}
|
|
|
|
$processor = new ExtensionProcessor();
|
|
$processor->extractInfo( $this->dir, self::$default + [
|
|
'namespaces' => [
|
|
[
|
|
'id' => 332200,
|
|
'constant' => 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A',
|
|
'name' => 'Test_A',
|
|
'defaultcontentmodel' => 'TestModel',
|
|
'gender' => [
|
|
'male' => 'Male test',
|
|
'female' => 'Female test',
|
|
],
|
|
'subpages' => true,
|
|
'content' => true,
|
|
'protection' => 'userright',
|
|
],
|
|
[ // Test_X will use ID 123456 not 334400
|
|
'id' => 334400,
|
|
'constant' => 'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X',
|
|
'name' => 'Test_X',
|
|
'defaultcontentmodel' => 'TestModel'
|
|
],
|
|
]
|
|
], 1 );
|
|
|
|
$extracted = $processor->getExtractedInfo();
|
|
|
|
$this->assertArrayHasKey(
|
|
'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A',
|
|
$extracted['defines']
|
|
);
|
|
$this->assertArrayNotHasKey(
|
|
'MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_X',
|
|
$extracted['defines']
|
|
);
|
|
|
|
$this->assertSame(
|
|
$extracted['defines']['MW_EXTENSION_PROCESSOR_TEST_EXTRACT_INFO_A'],
|
|
332200
|
|
);
|
|
|
|
$this->assertArrayHasKey( 'ExtensionNamespaces', $extracted['attributes'] );
|
|
$this->assertArrayHasKey( 123456, $extracted['attributes']['ExtensionNamespaces'] );
|
|
$this->assertArrayHasKey( 332200, $extracted['attributes']['ExtensionNamespaces'] );
|
|
$this->assertArrayNotHasKey( 334400, $extracted['attributes']['ExtensionNamespaces'] );
|
|
|
|
$this->assertSame( 'Test_X', $extracted['attributes']['ExtensionNamespaces'][123456] );
|
|
$this->assertSame( 'Test_A', $extracted['attributes']['ExtensionNamespaces'][332200] );
|
|
$this->assertSame(
|
|
[ 'male' => 'Male test', 'female' => 'Female test' ],
|
|
$extracted['globals']['wgExtraGenderNamespaces'][332200]
|
|
);
|
|
// A has subpages, X does not
|
|
$this->assertTrue( $extracted['globals']['wgNamespacesWithSubpages'][332200] );
|
|
$this->assertArrayNotHasKey( 123456, $extracted['globals']['wgNamespacesWithSubpages'] );
|
|
}
|
|
|
|
public static function provideRegisterHooks() {
|
|
$merge = [ ExtensionRegistry::MERGE_STRATEGY => 'array_merge_recursive' ];
|
|
// Format:
|
|
// Current $wgHooks
|
|
// Content in extension.json
|
|
// Expected value of $wgHooks
|
|
return [
|
|
// No hooks
|
|
[
|
|
[],
|
|
self::$default,
|
|
$merge,
|
|
],
|
|
// No current hooks, adding one for "FooBaz" in string format
|
|
[
|
|
[],
|
|
[ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
|
|
[ 'FooBaz' => [ 'FooBazCallback' ] ] + $merge,
|
|
],
|
|
// Hook for "FooBaz", adding another one
|
|
[
|
|
[ 'FooBaz' => [ 'PriorCallback' ] ],
|
|
[ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
|
|
[ 'FooBaz' => [ 'PriorCallback', 'FooBazCallback' ] ] + $merge,
|
|
],
|
|
// No current hooks, adding one for "FooBaz" in verbose array format
|
|
[
|
|
[],
|
|
[ 'Hooks' => [ 'FooBaz' => [ 'FooBazCallback' ] ] ] + self::$default,
|
|
[ 'FooBaz' => [ 'FooBazCallback' ] ] + $merge,
|
|
],
|
|
// Hook for "BarBaz", adding one for "FooBaz"
|
|
[
|
|
[ 'BarBaz' => [ 'BarBazCallback' ] ],
|
|
[ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self::$default,
|
|
[
|
|
'BarBaz' => [ 'BarBazCallback' ],
|
|
'FooBaz' => [ 'FooBazCallback' ],
|
|
] + $merge,
|
|
],
|
|
// Callbacks for FooBaz wrapped in an array
|
|
[
|
|
[],
|
|
[ 'Hooks' => [ 'FooBaz' => [ 'Callback1' ] ] ] + self::$default,
|
|
[
|
|
'FooBaz' => [ 'Callback1' ],
|
|
] + $merge,
|
|
],
|
|
// Multiple callbacks for FooBaz hook
|
|
[
|
|
[],
|
|
[ 'Hooks' => [ 'FooBaz' => [ 'Callback1', 'Callback2' ] ] ] + self::$default,
|
|
[
|
|
'FooBaz' => [ 'Callback1', 'Callback2' ],
|
|
] + $merge,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider provideRegisterHooks
|
|
*/
|
|
public function testRegisterHooks( $pre, $info, $expected ) {
|
|
$processor = new MockExtensionProcessor( [ 'wgHooks' => $pre ] );
|
|
$processor->extractInfo( $this->dir, $info, 1 );
|
|
$extracted = $processor->getExtractedInfo();
|
|
$this->assertEquals( $expected, $extracted['globals']['wgHooks'] );
|
|
}
|
|
|
|
public function testExtractConfig1() {
|
|
$processor = new ExtensionProcessor;
|
|
$info = [
|
|
'config' => [
|
|
'Bar' => 'somevalue',
|
|
'Foo' => 10,
|
|
'@IGNORED' => 'yes',
|
|
],
|
|
] + self::$default;
|
|
$info2 = [
|
|
'config' => [
|
|
'_prefix' => 'eg',
|
|
'Bar' => 'somevalue'
|
|
],
|
|
'name' => 'FooBar2',
|
|
];
|
|
$processor->extractInfo( $this->dir, $info, 1 );
|
|
$processor->extractInfo( $this->dir, $info2, 1 );
|
|
$extracted = $processor->getExtractedInfo();
|
|
$this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
|
|
$this->assertEquals( 10, $extracted['globals']['wgFoo'] );
|
|
$this->assertArrayNotHasKey( 'wg@IGNORED', $extracted['globals'] );
|
|
// Custom prefix:
|
|
$this->assertEquals( 'somevalue', $extracted['globals']['egBar'] );
|
|
}
|
|
|
|
public function testExtractConfig2() {
|
|
$processor = new ExtensionProcessor;
|
|
$info = [
|
|
'config' => [
|
|
'Bar' => [ 'value' => 'somevalue' ],
|
|
'Foo' => [ 'value' => 10 ],
|
|
'Path' => [ 'value' => 'foo.txt', 'path' => true ],
|
|
'Namespaces' => [
|
|
'value' => [
|
|
'10' => true,
|
|
'12' => false,
|
|
],
|
|
'merge_strategy' => 'array_plus',
|
|
],
|
|
],
|
|
] + self::$default;
|
|
$info2 = [
|
|
'config' => [
|
|
'Bar' => [ 'value' => 'somevalue' ],
|
|
],
|
|
'config_prefix' => 'eg',
|
|
'name' => 'FooBar2',
|
|
];
|
|
$processor->extractInfo( $this->dir, $info, 2 );
|
|
$processor->extractInfo( $this->dir, $info2, 2 );
|
|
$extracted = $processor->getExtractedInfo();
|
|
$this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
|
|
$this->assertEquals( 10, $extracted['globals']['wgFoo'] );
|
|
$this->assertEquals( "{$this->dirname}/foo.txt", $extracted['globals']['wgPath'] );
|
|
// Custom prefix:
|
|
$this->assertEquals( 'somevalue', $extracted['globals']['egBar'] );
|
|
$this->assertSame(
|
|
[ 10 => true, 12 => false, ExtensionRegistry::MERGE_STRATEGY => 'array_plus' ],
|
|
$extracted['globals']['wgNamespaces']
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @expectedException RuntimeException
|
|
*/
|
|
public function testDuplicateConfigKey1() {
|
|
$processor = new ExtensionProcessor;
|
|
$info = [
|
|
'config' => [
|
|
'Bar' => '',
|
|
]
|
|
] + self::$default;
|
|
$info2 = [
|
|
'config' => [
|
|
'Bar' => 'g',
|
|
],
|
|
'name' => 'FooBar2',
|
|
];
|
|
$processor->extractInfo( $this->dir, $info, 1 );
|
|
$processor->extractInfo( $this->dir, $info2, 1 );
|
|
}
|
|
|
|
/**
|
|
* @expectedException RuntimeException
|
|
*/
|
|
public function testDuplicateConfigKey2() {
|
|
$processor = new ExtensionProcessor;
|
|
$info = [
|
|
'config' => [
|
|
'Bar' => [ 'value' => 'somevalue' ],
|
|
]
|
|
] + self::$default;
|
|
$info2 = [
|
|
'config' => [
|
|
'Bar' => [ 'value' => 'somevalue' ],
|
|
],
|
|
'name' => 'FooBar2',
|
|
];
|
|
$processor->extractInfo( $this->dir, $info, 2 );
|
|
$processor->extractInfo( $this->dir, $info2, 2 );
|
|
}
|
|
|
|
public static function provideExtractExtensionMessagesFiles() {
|
|
$dir = __DIR__ . '/FooBar/';
|
|
return [
|
|
[
|
|
[ 'ExtensionMessagesFiles' => [ 'FooBarAlias' => 'FooBar.alias.php' ] ],
|
|
[ 'wgExtensionMessagesFiles' => [ 'FooBarAlias' => $dir . 'FooBar.alias.php' ] ]
|
|
],
|
|
[
|
|
[
|
|
'ExtensionMessagesFiles' => [
|
|
'FooBarAlias' => 'FooBar.alias.php',
|
|
'FooBarMagic' => 'FooBar.magic.i18n.php',
|
|
],
|
|
],
|
|
[
|
|
'wgExtensionMessagesFiles' => [
|
|
'FooBarAlias' => $dir . 'FooBar.alias.php',
|
|
'FooBarMagic' => $dir . 'FooBar.magic.i18n.php',
|
|
],
|
|
],
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider provideExtractExtensionMessagesFiles
|
|
*/
|
|
public function testExtractExtensionMessagesFiles( $input, $expected ) {
|
|
$processor = new ExtensionProcessor();
|
|
$processor->extractInfo( $this->dir, $input + self::$default, 1 );
|
|
$out = $processor->getExtractedInfo();
|
|
foreach ( $expected as $key => $value ) {
|
|
$this->assertEquals( $value, $out['globals'][$key] );
|
|
}
|
|
}
|
|
|
|
public static function provideExtractMessagesDirs() {
|
|
$dir = __DIR__ . '/FooBar/';
|
|
return [
|
|
[
|
|
[ 'MessagesDirs' => [ 'VisualEditor' => 'i18n' ] ],
|
|
[ 'wgMessagesDirs' => [ 'VisualEditor' => [ $dir . 'i18n' ] ] ]
|
|
],
|
|
[
|
|
[ 'MessagesDirs' => [ 'VisualEditor' => [ 'i18n', 'foobar' ] ] ],
|
|
[ 'wgMessagesDirs' => [ 'VisualEditor' => [ $dir . 'i18n', $dir . 'foobar' ] ] ]
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider provideExtractMessagesDirs
|
|
*/
|
|
public function testExtractMessagesDirs( $input, $expected ) {
|
|
$processor = new ExtensionProcessor();
|
|
$processor->extractInfo( $this->dir, $input + self::$default, 1 );
|
|
$out = $processor->getExtractedInfo();
|
|
foreach ( $expected as $key => $value ) {
|
|
$this->assertEquals( $value, $out['globals'][$key] );
|
|
}
|
|
}
|
|
|
|
public function testExtractCredits() {
|
|
$processor = new ExtensionProcessor();
|
|
$processor->extractInfo( $this->dir, self::$default, 1 );
|
|
$this->setExpectedException( Exception::class );
|
|
$processor->extractInfo( $this->dir, self::$default, 1 );
|
|
}
|
|
|
|
/**
|
|
* @dataProvider provideExtractResourceLoaderModules
|
|
*/
|
|
public function testExtractResourceLoaderModules( $input, $expected ) {
|
|
$processor = new ExtensionProcessor();
|
|
$processor->extractInfo( $this->dir, $input + self::$default, 1 );
|
|
$out = $processor->getExtractedInfo();
|
|
foreach ( $expected as $key => $value ) {
|
|
$this->assertEquals( $value, $out['globals'][$key] );
|
|
}
|
|
}
|
|
|
|
public static function provideExtractResourceLoaderModules() {
|
|
$dir = __DIR__ . '/FooBar';
|
|
return [
|
|
// Generic module with localBasePath/remoteExtPath specified
|
|
[
|
|
// Input
|
|
[
|
|
'ResourceModules' => [
|
|
'test.foo' => [
|
|
'styles' => 'foobar.js',
|
|
'localBasePath' => '',
|
|
'remoteExtPath' => 'FooBar',
|
|
],
|
|
],
|
|
],
|
|
// Expected
|
|
[
|
|
'wgResourceModules' => [
|
|
'test.foo' => [
|
|
'styles' => 'foobar.js',
|
|
'localBasePath' => $dir,
|
|
'remoteExtPath' => 'FooBar',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
// ResourceFileModulePaths specified:
|
|
[
|
|
// Input
|
|
[
|
|
'ResourceFileModulePaths' => [
|
|
'localBasePath' => 'modules',
|
|
'remoteExtPath' => 'FooBar/modules',
|
|
],
|
|
'ResourceModules' => [
|
|
// No paths
|
|
'test.foo' => [
|
|
'styles' => 'foo.js',
|
|
],
|
|
// Different paths set
|
|
'test.bar' => [
|
|
'styles' => 'bar.js',
|
|
'localBasePath' => 'subdir',
|
|
'remoteExtPath' => 'FooBar/subdir',
|
|
],
|
|
// Custom class with no paths set
|
|
'test.class' => [
|
|
'class' => 'FooBarModule',
|
|
'extra' => 'argument',
|
|
],
|
|
// Custom class with a localBasePath
|
|
'test.class.with.path' => [
|
|
'class' => 'FooBarPathModule',
|
|
'extra' => 'argument',
|
|
'localBasePath' => '',
|
|
]
|
|
],
|
|
],
|
|
// Expected
|
|
[
|
|
'wgResourceModules' => [
|
|
'test.foo' => [
|
|
'styles' => 'foo.js',
|
|
'localBasePath' => "$dir/modules",
|
|
'remoteExtPath' => 'FooBar/modules',
|
|
],
|
|
'test.bar' => [
|
|
'styles' => 'bar.js',
|
|
'localBasePath' => "$dir/subdir",
|
|
'remoteExtPath' => 'FooBar/subdir',
|
|
],
|
|
'test.class' => [
|
|
'class' => 'FooBarModule',
|
|
'extra' => 'argument',
|
|
'localBasePath' => "$dir/modules",
|
|
'remoteExtPath' => 'FooBar/modules',
|
|
],
|
|
'test.class.with.path' => [
|
|
'class' => 'FooBarPathModule',
|
|
'extra' => 'argument',
|
|
'localBasePath' => $dir,
|
|
'remoteExtPath' => 'FooBar/modules',
|
|
]
|
|
],
|
|
],
|
|
],
|
|
// ResourceModuleSkinStyles with file module paths
|
|
[
|
|
// Input
|
|
[
|
|
'ResourceFileModulePaths' => [
|
|
'localBasePath' => '',
|
|
'remoteSkinPath' => 'FooBar',
|
|
],
|
|
'ResourceModuleSkinStyles' => [
|
|
'foobar' => [
|
|
'test.foo' => 'foo.css',
|
|
]
|
|
],
|
|
],
|
|
// Expected
|
|
[
|
|
'wgResourceModuleSkinStyles' => [
|
|
'foobar' => [
|
|
'test.foo' => 'foo.css',
|
|
'localBasePath' => $dir,
|
|
'remoteSkinPath' => 'FooBar',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
// ResourceModuleSkinStyles with file module paths and an override
|
|
[
|
|
// Input
|
|
[
|
|
'ResourceFileModulePaths' => [
|
|
'localBasePath' => '',
|
|
'remoteSkinPath' => 'FooBar',
|
|
],
|
|
'ResourceModuleSkinStyles' => [
|
|
'foobar' => [
|
|
'test.foo' => 'foo.css',
|
|
'remoteSkinPath' => 'BarFoo'
|
|
],
|
|
],
|
|
],
|
|
// Expected
|
|
[
|
|
'wgResourceModuleSkinStyles' => [
|
|
'foobar' => [
|
|
'test.foo' => 'foo.css',
|
|
'localBasePath' => $dir,
|
|
'remoteSkinPath' => 'BarFoo',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
];
|
|
}
|
|
|
|
public static function provideSetToGlobal() {
|
|
return [
|
|
[
|
|
[ 'wgAPIModules', 'wgAvailableRights' ],
|
|
[],
|
|
[
|
|
'APIModules' => [ 'foobar' => 'ApiFooBar' ],
|
|
'AvailableRights' => [ 'foobar', 'unfoobar' ],
|
|
],
|
|
[
|
|
'wgAPIModules' => [ 'foobar' => 'ApiFooBar' ],
|
|
'wgAvailableRights' => [ 'foobar', 'unfoobar' ],
|
|
],
|
|
],
|
|
[
|
|
[ 'wgAPIModules', 'wgAvailableRights' ],
|
|
[
|
|
'wgAPIModules' => [ 'barbaz' => 'ApiBarBaz' ],
|
|
'wgAvailableRights' => [ 'barbaz' ]
|
|
],
|
|
[
|
|
'APIModules' => [ 'foobar' => 'ApiFooBar' ],
|
|
'AvailableRights' => [ 'foobar', 'unfoobar' ],
|
|
],
|
|
[
|
|
'wgAPIModules' => [ 'barbaz' => 'ApiBarBaz', 'foobar' => 'ApiFooBar' ],
|
|
'wgAvailableRights' => [ 'barbaz', 'foobar', 'unfoobar' ],
|
|
],
|
|
],
|
|
[
|
|
[ 'wgGroupPermissions' ],
|
|
[
|
|
'wgGroupPermissions' => [
|
|
'sysop' => [ 'delete' ]
|
|
],
|
|
],
|
|
[
|
|
'GroupPermissions' => [
|
|
'sysop' => [ 'undelete' ],
|
|
'user' => [ 'edit' ]
|
|
],
|
|
],
|
|
[
|
|
'wgGroupPermissions' => [
|
|
'sysop' => [ 'delete', 'undelete' ],
|
|
'user' => [ 'edit' ]
|
|
],
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Attributes under manifest_version 2
|
|
*/
|
|
public function testExtractAttributes() {
|
|
$processor = new ExtensionProcessor();
|
|
// Load FooBar extension
|
|
$processor->extractInfo( $this->dir, [ 'name' => 'FooBar' ], 2 );
|
|
$processor->extractInfo(
|
|
$this->dir,
|
|
[
|
|
'name' => 'Baz',
|
|
'attributes' => [
|
|
// Loaded
|
|
'FooBar' => [
|
|
'Plugins' => [
|
|
'ext.baz.foobar',
|
|
],
|
|
],
|
|
// Not loaded
|
|
'FizzBuzz' => [
|
|
'MorePlugins' => [
|
|
'ext.baz.fizzbuzz',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
2
|
|
);
|
|
|
|
$info = $processor->getExtractedInfo();
|
|
$this->assertArrayHasKey( 'FooBarPlugins', $info['attributes'] );
|
|
$this->assertSame( [ 'ext.baz.foobar' ], $info['attributes']['FooBarPlugins'] );
|
|
$this->assertArrayNotHasKey( 'FizzBuzzMorePlugins', $info['attributes'] );
|
|
}
|
|
|
|
/**
|
|
* Attributes under manifest_version 1
|
|
*/
|
|
public function testAttributes1() {
|
|
$processor = new ExtensionProcessor();
|
|
$processor->extractInfo(
|
|
$this->dir,
|
|
[
|
|
'name' => 'FooBar',
|
|
'FooBarPlugins' => [
|
|
'ext.baz.foobar',
|
|
],
|
|
'FizzBuzzMorePlugins' => [
|
|
'ext.baz.fizzbuzz',
|
|
],
|
|
],
|
|
1
|
|
);
|
|
$processor->extractInfo(
|
|
$this->dir,
|
|
[
|
|
'name' => 'FooBar2',
|
|
'FizzBuzzMorePlugins' => [
|
|
'ext.bar.fizzbuzz',
|
|
]
|
|
],
|
|
1
|
|
);
|
|
|
|
$info = $processor->getExtractedInfo();
|
|
$this->assertArrayHasKey( 'FooBarPlugins', $info['attributes'] );
|
|
$this->assertSame( [ 'ext.baz.foobar' ], $info['attributes']['FooBarPlugins'] );
|
|
$this->assertArrayHasKey( 'FizzBuzzMorePlugins', $info['attributes'] );
|
|
$this->assertSame(
|
|
[ 'ext.baz.fizzbuzz', 'ext.bar.fizzbuzz' ],
|
|
$info['attributes']['FizzBuzzMorePlugins']
|
|
);
|
|
}
|
|
|
|
public function testAttributes1_notarray() {
|
|
$processor = new ExtensionProcessor();
|
|
$this->setExpectedException(
|
|
InvalidArgumentException::class,
|
|
"The value for 'FooBarPlugins' should be an array (from {$this->dir})"
|
|
);
|
|
$processor->extractInfo(
|
|
$this->dir,
|
|
[
|
|
'FooBarPlugins' => 'ext.baz.foobar',
|
|
] + self::$default,
|
|
1
|
|
);
|
|
}
|
|
|
|
public function testExtractPathBasedGlobal() {
|
|
$processor = new ExtensionProcessor();
|
|
$processor->extractInfo(
|
|
$this->dir,
|
|
[
|
|
'ParserTestFiles' => [
|
|
'tests/parserTests.txt',
|
|
'tests/extraParserTests.txt',
|
|
],
|
|
'ServiceWiringFiles' => [
|
|
'includes/ServiceWiring.php'
|
|
],
|
|
] + self::$default,
|
|
1
|
|
);
|
|
$globals = $processor->getExtractedInfo()['globals'];
|
|
$this->assertArrayHasKey( 'wgParserTestFiles', $globals );
|
|
$this->assertSame( [
|
|
"{$this->dirname}/tests/parserTests.txt",
|
|
"{$this->dirname}/tests/extraParserTests.txt"
|
|
], $globals['wgParserTestFiles'] );
|
|
$this->assertArrayHasKey( 'wgServiceWiringFiles', $globals );
|
|
$this->assertSame( [
|
|
"{$this->dirname}/includes/ServiceWiring.php"
|
|
], $globals['wgServiceWiringFiles'] );
|
|
}
|
|
|
|
public function testGetRequirements() {
|
|
$info = self::$default + [
|
|
'requires' => [
|
|
'MediaWiki' => '>= 1.25.0',
|
|
'platform' => [
|
|
'php' => '>= 5.5.9'
|
|
],
|
|
'extensions' => [
|
|
'Bar' => '*'
|
|
]
|
|
]
|
|
];
|
|
$processor = new ExtensionProcessor();
|
|
$this->assertSame(
|
|
$info['requires'],
|
|
$processor->getRequirements( $info )
|
|
);
|
|
$this->assertSame(
|
|
[],
|
|
$processor->getRequirements( [] )
|
|
);
|
|
}
|
|
|
|
public function testGetExtraAutoloaderPaths() {
|
|
$processor = new ExtensionProcessor();
|
|
$this->assertSame(
|
|
[ "{$this->dirname}/vendor/autoload.php" ],
|
|
$processor->getExtraAutoloaderPaths( $this->dirname, [
|
|
'load_composer_autoloader' => true,
|
|
] )
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Verify that extension.schema.json is in sync with ExtensionProcessor
|
|
*
|
|
* @coversNothing
|
|
*/
|
|
public function testGlobalSettingsDocumentedInSchema() {
|
|
global $IP;
|
|
$globalSettings = TestingAccessWrapper::newFromClass(
|
|
ExtensionProcessor::class )->globalSettings;
|
|
|
|
$version = ExtensionRegistry::MANIFEST_VERSION;
|
|
$schema = FormatJson::decode(
|
|
file_get_contents( "$IP/docs/extension.schema.v$version.json" ),
|
|
true
|
|
);
|
|
$missing = [];
|
|
foreach ( $globalSettings as $global ) {
|
|
if ( !isset( $schema['properties'][$global] ) ) {
|
|
$missing[] = $global;
|
|
}
|
|
}
|
|
|
|
$this->assertEquals( [], $missing,
|
|
"The following global settings are not documented in docs/extension.schema.json" );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Allow overriding the default value of $this->globals
|
|
* so we can test merging
|
|
*/
|
|
class MockExtensionProcessor extends ExtensionProcessor {
|
|
public function __construct( $globals = [] ) {
|
|
$this->globals = $globals + $this->globals;
|
|
}
|
|
}
|