Import: Handle uploads with sha1 starting with 0 properly
[mediawiki.git] / tests / phpunit / includes / registration / ExtensionProcessorTest.php
blob590644fc0630f4dfa6ef1c69cfa56b8f5212fdde
1 <?php
3 class ExtensionProcessorTest extends MediaWikiTestCase {
5 private $dir;
7 public function setUp() {
8 parent::setUp();
9 $this->dir = __DIR__ . '/FooBar/extension.json';
12 /**
13 * 'name' is absolutely required
15 * @var array
17 public static $default = array(
18 'name' => 'FooBar',
21 /**
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 + array(
28 '@metadata' => array( 'foobarbaz' ),
29 'AnAttribute' => array( 'omg' ),
30 'AutoloadClasses' => array( 'FooBar' => 'includes/FooBar.php' ),
31 ), 1 );
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 = array( ExtensionRegistry::MERGE_STRATEGY => 'array_merge_recursive' );
42 // Format:
43 // Current $wgHooks
44 // Content in extension.json
45 // Expected value of $wgHooks
46 return array(
47 // No hooks
48 array(
49 array(),
50 self::$default,
51 $merge,
53 // No current hooks, adding one for "FooBaz"
54 array(
55 array(),
56 array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default,
57 array( 'FooBaz' => array( 'FooBazCallback' ) ) + $merge,
59 // Hook for "FooBaz", adding another one
60 array(
61 array( 'FooBaz' => array( 'PriorCallback' ) ),
62 array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default,
63 array( 'FooBaz' => array( 'PriorCallback', 'FooBazCallback' ) ) + $merge,
65 // Hook for "BarBaz", adding one for "FooBaz"
66 array(
67 array( 'BarBaz' => array( 'BarBazCallback' ) ),
68 array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default,
69 array(
70 'BarBaz' => array( 'BarBazCallback' ),
71 'FooBaz' => array( 'FooBazCallback' ),
72 ) + $merge,
74 // Callbacks for FooBaz wrapped in an array
75 array(
76 array(),
77 array( 'Hooks' => array( 'FooBaz' => array( 'Callback1' ) ) ) + self::$default,
78 array(
79 'FooBaz' => array( 'Callback1' ),
80 ) + $merge,
82 // Multiple callbacks for FooBaz hook
83 array(
84 array(),
85 array( 'Hooks' => array( 'FooBaz' => array( 'Callback1', 'Callback2' ) ) ) + self::$default,
86 array(
87 'FooBaz' => array( 'Callback1', 'Callback2' ),
88 ) + $merge,
93 /**
94 * @covers ExtensionProcessor::extractHooks
95 * @dataProvider provideRegisterHooks
97 public function testRegisterHooks( $pre, $info, $expected ) {
98 $processor = new MockExtensionProcessor( array( '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;
109 $info = array(
110 'config' => array(
111 'Bar' => 'somevalue',
112 'Foo' => 10,
113 '@IGNORED' => 'yes',
115 ) + self::$default;
116 $info2 = array(
117 'config' => array(
118 '_prefix' => 'eg',
119 'Bar' => 'somevalue'
121 'name' => 'FooBar2',
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'] );
129 // Custom prefix:
130 $this->assertEquals( 'somevalue', $extracted['globals']['egBar'] );
133 public static function provideExtracttExtensionMessagesFiles() {
134 $dir = __DIR__ . '/FooBar/';
135 return array(
136 array(
137 array( 'ExtensionMessagesFiles' => array( 'FooBarAlias' => 'FooBar.alias.php' ) ),
138 array( 'wgExtensionMessagesFiles' => array( 'FooBarAlias' => $dir . 'FooBar.alias.php' ) )
140 array(
141 array(
142 'ExtensionMessagesFiles' => array(
143 'FooBarAlias' => 'FooBar.alias.php',
144 'FooBarMagic' => 'FooBar.magic.i18n.php',
147 array(
148 'wgExtensionMessagesFiles' => array(
149 'FooBarAlias' => $dir . 'FooBar.alias.php',
150 'FooBarMagic' => $dir . 'FooBar.magic.i18n.php',
158 * @covers ExtensionProcessor::extracttExtensionMessagesFiles
159 * @dataProvider provideExtracttExtensionMessagesFiles
161 public function testExtracttExtensionMessagesFiles( $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/';
172 return array(
173 array(
174 array( 'MessagesDirs' => array( 'VisualEditor' => 'i18n' ) ),
175 array( 'wgMessagesDirs' => array( 'VisualEditor' => array( $dir . 'i18n' ) ) )
177 array(
178 array( 'MessagesDirs' => array( 'VisualEditor' => array( 'i18n', 'foobar' ) ) ),
179 array( 'wgMessagesDirs' => array( 'VisualEditor' => array( $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/';
222 return array(
223 // Generic module with localBasePath/remoteExtPath specified
224 array(
225 // Input
226 array(
227 'ResourceModules' => array(
228 'test.foo' => array(
229 'styles' => 'foobar.js',
230 'localBasePath' => '',
231 'remoteExtPath' => 'FooBar',
235 // Expected
236 array(
237 'wgResourceModules' => array(
238 'test.foo' => array(
239 'styles' => 'foobar.js',
240 'localBasePath' => $dir,
241 'remoteExtPath' => 'FooBar',
246 // ResourceFileModulePaths specified:
247 array(
248 // Input
249 array(
250 'ResourceFileModulePaths' => array(
251 'localBasePath' => '',
252 'remoteExtPath' => 'FooBar',
254 'ResourceModules' => array(
255 // No paths
256 'test.foo' => array(
257 'styles' => 'foo.js',
259 // Different paths set
260 'test.bar' => array(
261 'styles' => 'bar.js',
262 'localBasePath' => 'subdir',
263 'remoteExtPath' => 'FooBar/subdir',
265 // Custom class with no paths set
266 'test.class' => array(
267 'class' => 'FooBarModule',
268 'extra' => 'argument',
270 // Custom class with a localBasePath
271 'test.class.with.path' => array(
272 'class' => 'FooBarPathModule',
273 'extra' => 'argument',
274 'localBasePath' => '',
278 // Expected
279 array(
280 'wgResourceModules' => array(
281 'test.foo' => array(
282 'styles' => 'foo.js',
283 'localBasePath' => $dir,
284 'remoteExtPath' => 'FooBar',
286 'test.bar' => array(
287 'styles' => 'bar.js',
288 'localBasePath' => $dir . 'subdir',
289 'remoteExtPath' => 'FooBar/subdir',
291 'test.class' => array(
292 'class' => 'FooBarModule',
293 'extra' => 'argument',
294 'localBasePath' => $dir,
295 'remoteExtPath' => 'FooBar',
297 'test.class.with.path' => array(
298 'class' => 'FooBarPathModule',
299 'extra' => 'argument',
300 'localBasePath' => $dir,
301 'remoteExtPath' => 'FooBar',
306 // ResourceModuleSkinStyles with file module paths
307 array(
308 // Input
309 array(
310 'ResourceFileModulePaths' => array(
311 'localBasePath' => '',
312 'remoteSkinPath' => 'FooBar',
314 'ResourceModuleSkinStyles' => array(
315 'foobar' => array(
316 'test.foo' => 'foo.css',
320 // Expected
321 array(
322 'wgResourceModuleSkinStyles' => array(
323 'foobar' => array(
324 'test.foo' => 'foo.css',
325 'localBasePath' => $dir,
326 'remoteSkinPath' => 'FooBar',
331 // ResourceModuleSkinStyles with file module paths and an override
332 array(
333 // Input
334 array(
335 'ResourceFileModulePaths' => array(
336 'localBasePath' => '',
337 'remoteSkinPath' => 'FooBar',
339 'ResourceModuleSkinStyles' => array(
340 'foobar' => array(
341 'test.foo' => 'foo.css',
342 'remoteSkinPath' => 'BarFoo'
346 // Expected
347 array(
348 'wgResourceModuleSkinStyles' => array(
349 'foobar' => array(
350 'test.foo' => 'foo.css',
351 'localBasePath' => $dir,
352 'remoteSkinPath' => 'BarFoo',
360 public static function provideSetToGlobal() {
361 return array(
362 array(
363 array( 'wgAPIModules', 'wgAvailableRights' ),
364 array(),
365 array(
366 'APIModules' => array( 'foobar' => 'ApiFooBar' ),
367 'AvailableRights' => array( 'foobar', 'unfoobar' ),
369 array(
370 'wgAPIModules' => array( 'foobar' => 'ApiFooBar' ),
371 'wgAvailableRights' => array( 'foobar', 'unfoobar' ),
374 array(
375 array( 'wgAPIModules', 'wgAvailableRights' ),
376 array(
377 'wgAPIModules' => array( 'barbaz' => 'ApiBarBaz' ),
378 'wgAvailableRights' => array( 'barbaz' )
380 array(
381 'APIModules' => array( 'foobar' => 'ApiFooBar' ),
382 'AvailableRights' => array( 'foobar', 'unfoobar' ),
384 array(
385 'wgAPIModules' => array( 'barbaz' => 'ApiBarBaz', 'foobar' => 'ApiFooBar' ),
386 'wgAvailableRights' => array( 'barbaz', 'foobar', 'unfoobar' ),
389 array(
390 array( 'wgGroupPermissions' ),
391 array(
392 'wgGroupPermissions' => array(
393 'sysop' => array( 'delete' )
396 array(
397 'GroupPermissions' => array(
398 'sysop' => array( 'undelete' ),
399 'user' => array( 'edit' )
402 array(
403 'wgGroupPermissions' => array(
404 'sysop' => array( 'delete', 'undelete' ),
405 'user' => array( 'edit' )
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 = array() ) {
419 $this->globals = $globals + $this->globals;