Merge "Provide command to adjust phpunit.xml for code coverage"
[lhc/web/wiklou.git] / tests / phpunit / includes / registration / ExtensionRegistryTest.php
1 <?php
2
3 use Wikimedia\ScopedCallback;
4
5 /**
6 * @covers ExtensionRegistry
7 */
8 class ExtensionRegistryTest extends MediaWikiTestCase {
9
10 private $dataDir;
11
12 public function setUp() {
13 parent::setUp();
14 $this->dataDir = __DIR__ . '/../../data/registration';
15 }
16
17 public function testQueue_invalid() {
18 $registry = new ExtensionRegistry();
19 $path = __DIR__ . '/doesnotexist.json';
20 $this->setExpectedException(
21 Exception::class,
22 "file $path"
23 );
24 $registry->queue( $path );
25 }
26
27 public function testQueue() {
28 $registry = new ExtensionRegistry();
29 $path = "{$this->dataDir}/good.json";
30 $registry->queue( $path );
31 $this->assertArrayHasKey(
32 $path,
33 $registry->getQueue()
34 );
35 $registry->clearQueue();
36 $this->assertEmpty( $registry->getQueue() );
37 }
38
39 public function testLoadFromQueue_empty() {
40 $registry = new ExtensionRegistry();
41 $registry->loadFromQueue();
42 $this->assertEmpty( $registry->getAllThings() );
43 }
44
45 public function testLoadFromQueue_late() {
46 $registry = new ExtensionRegistry();
47 $registry->finish();
48 $registry->queue( "{$this->dataDir}/good.json" );
49 $this->setExpectedException(
50 MWException::class,
51 "The following paths tried to load late: {$this->dataDir}/good.json"
52 );
53 $registry->loadFromQueue();
54 }
55
56 public function testLoadFromQueue() {
57 $registry = new ExtensionRegistry();
58 $registry->queue( "{$this->dataDir}/good.json" );
59 $registry->loadFromQueue();
60 $this->assertArrayHasKey( 'FooBar', $registry->getAllThings() );
61 $this->assertTrue( $registry->isLoaded( 'FooBar' ) );
62 $this->assertTrue( $registry->isLoaded( 'FooBar', '*' ) );
63 $this->assertSame( [ 'test' ], $registry->getAttribute( 'FooBarAttr' ) );
64 $this->assertSame( [], $registry->getAttribute( 'NotLoadedAttr' ) );
65 }
66
67 public function testLoadFromQueueWithConstraintWithVersion() {
68 $registry = new ExtensionRegistry();
69 $registry->queue( "{$this->dataDir}/good_with_version.json" );
70 $registry->loadFromQueue();
71 $this->assertTrue( $registry->isLoaded( 'FooBar', '>= 1.2.0' ) );
72 $this->assertFalse( $registry->isLoaded( 'FooBar', '^1.3.0' ) );
73 }
74
75 /**
76 * @expectedException LogicException
77 */
78 public function testLoadFromQueueWithConstraintWithoutVersion() {
79 $registry = new ExtensionRegistry();
80 $registry->queue( "{$this->dataDir}/good.json" );
81 $registry->loadFromQueue();
82 $registry->isLoaded( 'FooBar', '>= 1.2.0' );
83 }
84
85 /**
86 * @expectedException PHPUnit_Framework_Error
87 */
88 public function testReadFromQueue_nonexistent() {
89 $registry = new ExtensionRegistry();
90 $registry->readFromQueue( [
91 __DIR__ . '/doesnotexist.json' => 1
92 ] );
93 }
94
95 public function testReadFromQueueInitializeAutoloaderWithPsr4Namespaces() {
96 $registry = new ExtensionRegistry();
97 $registry->readFromQueue( [
98 "{$this->dataDir}/autoload_namespaces.json" => 1
99 ] );
100 $this->assertTrue(
101 class_exists( 'Test\\MediaWiki\\AutoLoader\\TestFooBar' ),
102 "Registry initializes Autoloader from AutoloadNamespaces"
103 );
104 }
105
106 /**
107 * @dataProvider provideExportExtractedDataGlobals
108 */
109 public function testExportExtractedDataGlobals( $desc, $before, $globals, $expected ) {
110 // Set globals for test
111 if ( $before ) {
112 foreach ( $before as $key => $value ) {
113 // mw prefixed globals does not exist normally
114 if ( substr( $key, 0, 2 ) == 'mw' ) {
115 $GLOBALS[$key] = $value;
116 } else {
117 $this->setMwGlobals( $key, $value );
118 }
119 }
120 }
121
122 $info = [
123 'globals' => $globals,
124 'callbacks' => [],
125 'defines' => [],
126 'credits' => [],
127 'attributes' => [],
128 'autoloaderPaths' => []
129 ];
130 $registry = new ExtensionRegistry();
131 $class = new ReflectionClass( ExtensionRegistry::class );
132 $method = $class->getMethod( 'exportExtractedData' );
133 $method->setAccessible( true );
134 $method->invokeArgs( $registry, [ $info ] );
135 foreach ( $expected as $name => $value ) {
136 $this->assertArrayHasKey( $name, $GLOBALS, $desc );
137 $this->assertEquals( $value, $GLOBALS[$name], $desc );
138 }
139
140 // Remove mw prefixed globals
141 if ( $before ) {
142 foreach ( $before as $key => $value ) {
143 if ( substr( $key, 0, 2 ) == 'mw' ) {
144 unset( $GLOBALS[$key] );
145 }
146 }
147 }
148 }
149
150 public static function provideExportExtractedDataGlobals() {
151 // "mwtest" prefix used instead of "$wg" to avoid potential conflicts
152 return [
153 [
154 'Simple non-array values',
155 [
156 'mwtestFooBarConfig' => true,
157 'mwtestFooBarConfig2' => 'string',
158 ],
159 [
160 'mwtestFooBarDefault' => 1234,
161 'mwtestFooBarConfig' => false,
162 ],
163 [
164 'mwtestFooBarConfig' => true,
165 'mwtestFooBarConfig2' => 'string',
166 'mwtestFooBarDefault' => 1234,
167 ],
168 ],
169 [
170 'No global already set, simple array',
171 null,
172 [
173 'mwtestDefaultOptions' => [
174 'foobar' => true,
175 ]
176 ],
177 [
178 'mwtestDefaultOptions' => [
179 'foobar' => true,
180 ]
181 ],
182 ],
183 [
184 'Global already set, simple array',
185 [
186 'mwtestDefaultOptions' => [
187 'foobar' => true,
188 'foo' => 'string'
189 ],
190 ],
191 [
192 'mwtestDefaultOptions' => [
193 'barbaz' => 12345,
194 'foobar' => false,
195 ],
196 ],
197 [
198 'mwtestDefaultOptions' => [
199 'barbaz' => 12345,
200 'foo' => 'string',
201 'foobar' => true,
202 ],
203 ]
204 ],
205 [
206 'Global already set, 1d array that appends',
207 [
208 'mwAvailableRights' => [
209 'foobar',
210 'foo'
211 ],
212 ],
213 [
214 'mwAvailableRights' => [
215 'barbaz',
216 ],
217 ],
218 [
219 'mwAvailableRights' => [
220 'barbaz',
221 'foobar',
222 'foo',
223 ],
224 ]
225 ],
226 [
227 'Global already set, array with integer keys',
228 [
229 'mwNamespacesFoo' => [
230 100 => true,
231 102 => false
232 ],
233 ],
234 [
235 'mwNamespacesFoo' => [
236 100 => false,
237 500 => true,
238 ExtensionRegistry::MERGE_STRATEGY => 'array_plus',
239 ],
240 ],
241 [
242 'mwNamespacesFoo' => [
243 100 => true,
244 102 => false,
245 500 => true,
246 ],
247 ]
248 ],
249 [
250 'No global already set, $wgHooks',
251 [
252 'wgHooks' => [],
253 ],
254 [
255 'wgHooks' => [
256 'FooBarEvent' => [
257 'FooBarClass::onFooBarEvent'
258 ],
259 ExtensionRegistry::MERGE_STRATEGY => 'array_merge_recursive'
260 ],
261 ],
262 [
263 'wgHooks' => [
264 'FooBarEvent' => [
265 'FooBarClass::onFooBarEvent'
266 ],
267 ],
268 ],
269 ],
270 [
271 'Global already set, $wgHooks',
272 [
273 'wgHooks' => [
274 'FooBarEvent' => [
275 'FooBarClass::onFooBarEvent'
276 ],
277 'BazBarEvent' => [
278 'FooBarClass::onBazBarEvent',
279 ],
280 ],
281 ],
282 [
283 'wgHooks' => [
284 'FooBarEvent' => [
285 'BazBarClass::onFooBarEvent',
286 ],
287 ExtensionRegistry::MERGE_STRATEGY => 'array_merge_recursive',
288 ],
289 ],
290 [
291 'wgHooks' => [
292 'FooBarEvent' => [
293 'FooBarClass::onFooBarEvent',
294 'BazBarClass::onFooBarEvent',
295 ],
296 'BazBarEvent' => [
297 'FooBarClass::onBazBarEvent',
298 ],
299 ],
300 ],
301 ],
302 [
303 'Global already set, $wgGroupPermissions',
304 [
305 'wgGroupPermissions' => [
306 'sysop' => [
307 'something' => true,
308 ],
309 'user' => [
310 'somethingtwo' => true,
311 ]
312 ],
313 ],
314 [
315 'wgGroupPermissions' => [
316 'customgroup' => [
317 'right' => true,
318 ],
319 'user' => [
320 'right' => true,
321 'somethingtwo' => false,
322 'nonduplicated' => true,
323 ],
324 ExtensionRegistry::MERGE_STRATEGY => 'array_plus_2d',
325 ],
326 ],
327 [
328 'wgGroupPermissions' => [
329 'customgroup' => [
330 'right' => true,
331 ],
332 'sysop' => [
333 'something' => true,
334 ],
335 'user' => [
336 'somethingtwo' => true,
337 'right' => true,
338 'nonduplicated' => true,
339 ]
340 ],
341 ],
342 ],
343 [
344 'False local setting should not be overridden (T100767)',
345 [
346 'mwtestT100767' => false,
347 ],
348 [
349 'mwtestT100767' => true,
350 ],
351 [
352 'mwtestT100767' => false,
353 ],
354 ],
355 [
356 'test array_replace_recursive',
357 [
358 'mwtestJsonConfigs' => [
359 'JsonZeroConfig' => [
360 'namespace' => 480,
361 'nsName' => 'Zero',
362 'isLocal' => true,
363 ],
364 ],
365 ],
366 [
367 'mwtestJsonConfigs' => [
368 'JsonZeroConfig' => [
369 'isLocal' => false,
370 'remote' => [
371 'username' => 'foo',
372 ],
373 ],
374 ExtensionRegistry::MERGE_STRATEGY => 'array_replace_recursive',
375 ],
376 ],
377 [
378 'mwtestJsonConfigs' => [
379 'JsonZeroConfig' => [
380 'namespace' => 480,
381 'nsName' => 'Zero',
382 'isLocal' => false,
383 'remote' => [
384 'username' => 'foo',
385 ],
386 ],
387 ],
388 ],
389 ],
390 [
391 'global is null before',
392 [
393 'NullGlobal' => null,
394 ],
395 [
396 'NullGlobal' => 'not-null'
397 ],
398 [
399 'NullGlobal' => null
400 ],
401 ],
402 ];
403 }
404
405 public function testSetAttributeForTest() {
406 $registry = new ExtensionRegistry();
407 $registry->queue( "{$this->dataDir}/good.json" );
408 $registry->loadFromQueue();
409 // Sanity check that it worked
410 $this->assertSame( [ 'test' ], $registry->getAttribute( 'FooBarAttr' ) );
411 $reset = $registry->setAttributeForTest( 'FooBarAttr', [ 'override' ] );
412 // overridden properly
413 $this->assertSame( [ 'override' ], $registry->getAttribute( 'FooBarAttr' ) );
414 ScopedCallback::consume( $reset );
415 // reset properly
416 $this->assertSame( [ 'test' ], $registry->getAttribute( 'FooBarAttr' ) );
417 }
418
419 /**
420 * @expectedException Exception
421 * @expectedExceptionMessage The attribute 'foo' has already been overridden
422 */
423 public function testSetAttributeForTestDuplicate() {
424 $registry = new ExtensionRegistry();
425 $reset1 = $registry->setAttributeForTest( 'foo', [ 'val1' ] );
426 $reset2 = $registry->setAttributeForTest( 'foo', [ 'val2' ] );
427 }
428 }