3 class ExtensionProcessorTest
extends MediaWikiTestCase
{
7 public function setUp() {
9 $this->dir
= __DIR__
. '/FooBar/extension.json';
13 * 'name' is absolutely required
17 public static $default = [
22 * @covers ExtensionProcessor::extractInfo
24 public function testExtractInfo() {
25 // Test that attributes that begin with @ are ignored
26 $processor = new ExtensionProcessor();
27 $processor->extractInfo( $this->dir
, self
::$default +
[
28 '@metadata' => [ 'foobarbaz' ],
29 'AnAttribute' => [ 'omg' ],
30 'AutoloadClasses' => [ 'FooBar' => 'includes/FooBar.php' ],
33 $extracted = $processor->getExtractedInfo();
34 $attributes = $extracted['attributes'];
35 $this->assertArrayHasKey( 'AnAttribute', $attributes );
36 $this->assertArrayNotHasKey( '@metadata', $attributes );
37 $this->assertArrayNotHasKey( 'AutoloadClasses', $attributes );
40 public static function provideRegisterHooks() {
41 $merge = [ ExtensionRegistry
::MERGE_STRATEGY
=> 'array_merge_recursive' ];
44 // Content in extension.json
45 // Expected value of $wgHooks
53 // No current hooks, adding one for "FooBaz"
56 [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self
::$default,
57 [ 'FooBaz' => [ 'FooBazCallback' ] ] +
$merge,
59 // Hook for "FooBaz", adding another one
61 [ 'FooBaz' => [ 'PriorCallback' ] ],
62 [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self
::$default,
63 [ 'FooBaz' => [ 'PriorCallback', 'FooBazCallback' ] ] +
$merge,
65 // Hook for "BarBaz", adding one for "FooBaz"
67 [ 'BarBaz' => [ 'BarBazCallback' ] ],
68 [ 'Hooks' => [ 'FooBaz' => 'FooBazCallback' ] ] + self
::$default,
70 'BarBaz' => [ 'BarBazCallback' ],
71 'FooBaz' => [ 'FooBazCallback' ],
74 // Callbacks for FooBaz wrapped in an array
77 [ 'Hooks' => [ 'FooBaz' => [ 'Callback1' ] ] ] + self
::$default,
79 'FooBaz' => [ 'Callback1' ],
82 // Multiple callbacks for FooBaz hook
85 [ 'Hooks' => [ 'FooBaz' => [ 'Callback1', 'Callback2' ] ] ] + self
::$default,
87 'FooBaz' => [ 'Callback1', 'Callback2' ],
94 * @covers ExtensionProcessor::extractHooks
95 * @dataProvider provideRegisterHooks
97 public function testRegisterHooks( $pre, $info, $expected ) {
98 $processor = new MockExtensionProcessor( [ 'wgHooks' => $pre ] );
99 $processor->extractInfo( $this->dir
, $info, 1 );
100 $extracted = $processor->getExtractedInfo();
101 $this->assertEquals( $expected, $extracted['globals']['wgHooks'] );
105 * @covers ExtensionProcessor::extractConfig
107 public function testExtractConfig() {
108 $processor = new ExtensionProcessor
;
111 'Bar' => 'somevalue',
123 $processor->extractInfo( $this->dir
, $info, 1 );
124 $processor->extractInfo( $this->dir
, $info2, 1 );
125 $extracted = $processor->getExtractedInfo();
126 $this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
127 $this->assertEquals( 10, $extracted['globals']['wgFoo'] );
128 $this->assertArrayNotHasKey( 'wg@IGNORED', $extracted['globals'] );
130 $this->assertEquals( 'somevalue', $extracted['globals']['egBar'] );
133 public static function provideExtractExtensionMessagesFiles() {
134 $dir = __DIR__
. '/FooBar/';
137 [ 'ExtensionMessagesFiles' => [ 'FooBarAlias' => 'FooBar.alias.php' ] ],
138 [ 'wgExtensionMessagesFiles' => [ 'FooBarAlias' => $dir . 'FooBar.alias.php' ] ]
142 'ExtensionMessagesFiles' => [
143 'FooBarAlias' => 'FooBar.alias.php',
144 'FooBarMagic' => 'FooBar.magic.i18n.php',
148 'wgExtensionMessagesFiles' => [
149 'FooBarAlias' => $dir . 'FooBar.alias.php',
150 'FooBarMagic' => $dir . 'FooBar.magic.i18n.php',
158 * @covers ExtensionProcessor::extractExtensionMessagesFiles
159 * @dataProvider provideExtractExtensionMessagesFiles
161 public function testExtractExtensionMessagesFiles( $input, $expected ) {
162 $processor = new ExtensionProcessor();
163 $processor->extractInfo( $this->dir
, $input + self
::$default, 1 );
164 $out = $processor->getExtractedInfo();
165 foreach ( $expected as $key => $value ) {
166 $this->assertEquals( $value, $out['globals'][$key] );
170 public static function provideExtractMessagesDirs() {
171 $dir = __DIR__
. '/FooBar/';
174 [ 'MessagesDirs' => [ 'VisualEditor' => 'i18n' ] ],
175 [ 'wgMessagesDirs' => [ 'VisualEditor' => [ $dir . 'i18n' ] ] ]
178 [ 'MessagesDirs' => [ 'VisualEditor' => [ 'i18n', 'foobar' ] ] ],
179 [ 'wgMessagesDirs' => [ 'VisualEditor' => [ $dir . 'i18n', $dir . 'foobar' ] ] ]
185 * @covers ExtensionProcessor::extractMessagesDirs
186 * @dataProvider provideExtractMessagesDirs
188 public function testExtractMessagesDirs( $input, $expected ) {
189 $processor = new ExtensionProcessor();
190 $processor->extractInfo( $this->dir
, $input + self
::$default, 1 );
191 $out = $processor->getExtractedInfo();
192 foreach ( $expected as $key => $value ) {
193 $this->assertEquals( $value, $out['globals'][$key] );
198 * @covers ExtensionProcessor::extractCredits
200 public function testExtractCredits() {
201 $processor = new ExtensionProcessor();
202 $processor->extractInfo( $this->dir
, self
::$default, 1 );
203 $this->setExpectedException( 'Exception' );
204 $processor->extractInfo( $this->dir
, self
::$default, 1 );
208 * @covers ExtensionProcessor::extractResourceLoaderModules
209 * @dataProvider provideExtractResourceLoaderModules
211 public function testExtractResourceLoaderModules( $input, $expected ) {
212 $processor = new ExtensionProcessor();
213 $processor->extractInfo( $this->dir
, $input + self
::$default, 1 );
214 $out = $processor->getExtractedInfo();
215 foreach ( $expected as $key => $value ) {
216 $this->assertEquals( $value, $out['globals'][$key] );
220 public static function provideExtractResourceLoaderModules() {
221 $dir = __DIR__
. '/FooBar';
223 // Generic module with localBasePath/remoteExtPath specified
227 'ResourceModules' => [
229 'styles' => 'foobar.js',
230 'localBasePath' => '',
231 'remoteExtPath' => 'FooBar',
237 'wgResourceModules' => [
239 'styles' => 'foobar.js',
240 'localBasePath' => $dir,
241 'remoteExtPath' => 'FooBar',
246 // ResourceFileModulePaths specified:
250 'ResourceFileModulePaths' => [
251 'localBasePath' => '',
252 'remoteExtPath' => 'FooBar',
254 'ResourceModules' => [
257 'styles' => 'foo.js',
259 // Different paths set
261 'styles' => 'bar.js',
262 'localBasePath' => 'subdir',
263 'remoteExtPath' => 'FooBar/subdir',
265 // Custom class with no paths set
267 'class' => 'FooBarModule',
268 'extra' => 'argument',
270 // Custom class with a localBasePath
271 'test.class.with.path' => [
272 'class' => 'FooBarPathModule',
273 'extra' => 'argument',
274 'localBasePath' => '',
280 'wgResourceModules' => [
282 'styles' => 'foo.js',
283 'localBasePath' => $dir,
284 'remoteExtPath' => 'FooBar',
287 'styles' => 'bar.js',
288 'localBasePath' => "$dir/subdir",
289 'remoteExtPath' => 'FooBar/subdir',
292 'class' => 'FooBarModule',
293 'extra' => 'argument',
294 'localBasePath' => $dir,
295 'remoteExtPath' => 'FooBar',
297 'test.class.with.path' => [
298 'class' => 'FooBarPathModule',
299 'extra' => 'argument',
300 'localBasePath' => $dir,
301 'remoteExtPath' => 'FooBar',
306 // ResourceModuleSkinStyles with file module paths
310 'ResourceFileModulePaths' => [
311 'localBasePath' => '',
312 'remoteSkinPath' => 'FooBar',
314 'ResourceModuleSkinStyles' => [
316 'test.foo' => 'foo.css',
322 'wgResourceModuleSkinStyles' => [
324 'test.foo' => 'foo.css',
325 'localBasePath' => $dir,
326 'remoteSkinPath' => 'FooBar',
331 // ResourceModuleSkinStyles with file module paths and an override
335 'ResourceFileModulePaths' => [
336 'localBasePath' => '',
337 'remoteSkinPath' => 'FooBar',
339 'ResourceModuleSkinStyles' => [
341 'test.foo' => 'foo.css',
342 'remoteSkinPath' => 'BarFoo'
348 'wgResourceModuleSkinStyles' => [
350 'test.foo' => 'foo.css',
351 'localBasePath' => $dir,
352 'remoteSkinPath' => 'BarFoo',
360 public static function provideSetToGlobal() {
363 [ 'wgAPIModules', 'wgAvailableRights' ],
366 'APIModules' => [ 'foobar' => 'ApiFooBar' ],
367 'AvailableRights' => [ 'foobar', 'unfoobar' ],
370 'wgAPIModules' => [ 'foobar' => 'ApiFooBar' ],
371 'wgAvailableRights' => [ 'foobar', 'unfoobar' ],
375 [ 'wgAPIModules', 'wgAvailableRights' ],
377 'wgAPIModules' => [ 'barbaz' => 'ApiBarBaz' ],
378 'wgAvailableRights' => [ 'barbaz' ]
381 'APIModules' => [ 'foobar' => 'ApiFooBar' ],
382 'AvailableRights' => [ 'foobar', 'unfoobar' ],
385 'wgAPIModules' => [ 'barbaz' => 'ApiBarBaz', 'foobar' => 'ApiFooBar' ],
386 'wgAvailableRights' => [ 'barbaz', 'foobar', 'unfoobar' ],
390 [ 'wgGroupPermissions' ],
392 'wgGroupPermissions' => [
393 'sysop' => [ 'delete' ]
397 'GroupPermissions' => [
398 'sysop' => [ 'undelete' ],
403 'wgGroupPermissions' => [
404 'sysop' => [ 'delete', 'undelete' ],
414 * Allow overriding the default value of $this->globals
415 * so we can test merging
417 class MockExtensionProcessor
extends ExtensionProcessor
{
418 public function __construct( $globals = [] ) {
419 $this->globals
= $globals +
$this->globals
;