Merge "Fix use of GenderCache in ApiPageSet::processTitlesArray"
[lhc/web/wiklou.git] / tests / phpunit / includes / api / ApiModuleManagerTest.php
1 <?php
2
3 use MediaWiki\MediaWikiServices;
4 use Wikimedia\ObjectFactory;
5
6 /**
7 * @covers ApiModuleManager
8 *
9 * @group API
10 * @group Database
11 * @group medium
12 */
13 class ApiModuleManagerTest extends MediaWikiTestCase {
14
15 private function getModuleManager() {
16 $request = new FauxRequest();
17 $main = new ApiMain( $request );
18
19 return new ApiModuleManager( $main, MediaWikiServices::getInstance()->getObjectFactory() );
20 }
21
22 public function newApiLogin( $main, $action ) {
23 return new ApiLogin( $main, $action );
24 }
25
26 public function addModuleProvider() {
27 return [
28 'plain class' => [
29 'login',
30 'action',
31 ApiLogin::class,
32 null,
33 ],
34
35 'with class and factory' => [
36 'login',
37 'action',
38 ApiLogin::class,
39 [ $this, 'newApiLogin' ],
40 ],
41
42 'with spec (class only)' => [
43 'login',
44 'action',
45 [
46 'class' => ApiLogin::class
47 ],
48 null,
49 ],
50
51 'with spec' => [
52 'login',
53 'action',
54 [
55 'class' => ApiLogin::class,
56 'factory' => [ $this, 'newApiLogin' ],
57 ],
58 null,
59 ],
60
61 'with spec (using services)' => [
62 'logout',
63 'action',
64 [
65 'class' => ApiLogout::class,
66 'factory' => function ( ApiMain $main, $action, ObjectFactory $objectFactory ) {
67 return new ApiLogout( $main, $action );
68 },
69 'services' => [
70 'ObjectFactory'
71 ],
72 ],
73 null,
74 ]
75 ];
76 }
77
78 /**
79 * @dataProvider addModuleProvider
80 */
81 public function testAddModule( $name, $group, $spec, $factory ) {
82 $moduleManager = $this->getModuleManager();
83 $moduleManager->addModule( $name, $group, $spec, $factory );
84
85 $this->assertTrue( $moduleManager->isDefined( $name, $group ), 'isDefined' );
86 $this->assertNotNull( $moduleManager->getModule( $name, $group, true ), 'getModule' );
87 }
88
89 public function addModulesProvider() {
90 return [
91 'empty' => [
92 [],
93 'action',
94 ],
95
96 'simple' => [
97 [
98 'login' => ApiLogin::class,
99 'logout' => ApiLogout::class,
100 ],
101 'action',
102 ],
103
104 'with factories' => [
105 [
106 'login' => [
107 'class' => ApiLogin::class,
108 'factory' => [ $this, 'newApiLogin' ],
109 ],
110 'logout' => [
111 'class' => ApiLogout::class,
112 'factory' => function ( ApiMain $main, $action ) {
113 return new ApiLogout( $main, $action );
114 },
115 ],
116 ],
117 'action',
118 ],
119 ];
120 }
121
122 /**
123 * @dataProvider addModulesProvider
124 */
125 public function testAddModules( array $modules, $group ) {
126 $moduleManager = $this->getModuleManager();
127 $moduleManager->addModules( $modules, $group );
128
129 foreach ( array_keys( $modules ) as $name ) {
130 $this->assertTrue( $moduleManager->isDefined( $name, $group ), 'isDefined' );
131 $this->assertNotNull( $moduleManager->getModule( $name, $group, true ), 'getModule' );
132 }
133
134 $this->assertTrue( true ); // Don't mark the test as risky if $modules is empty
135 }
136
137 public function getModuleProvider() {
138 $modules = [
139 'feedrecentchanges' => ApiFeedRecentChanges::class,
140 'feedcontributions' => [ 'class' => ApiFeedContributions::class ],
141 'login' => [
142 'class' => ApiLogin::class,
143 'factory' => [ $this, 'newApiLogin' ],
144 ],
145 'logout' => [
146 'class' => ApiLogout::class,
147 'factory' => function ( ApiMain $main, $action ) {
148 return new ApiLogout( $main, $action );
149 },
150 ],
151 ];
152
153 return [
154 'legacy entry' => [
155 $modules,
156 'feedrecentchanges',
157 ApiFeedRecentChanges::class,
158 ],
159
160 'just a class' => [
161 $modules,
162 'feedcontributions',
163 ApiFeedContributions::class,
164 ],
165
166 'with factory' => [
167 $modules,
168 'login',
169 ApiLogin::class,
170 ],
171
172 'with closure' => [
173 $modules,
174 'logout',
175 ApiLogout::class,
176 ],
177 ];
178 }
179
180 /**
181 * @covers ApiModuleManager::getModule
182 * @dataProvider getModuleProvider
183 */
184 public function testGetModule( $modules, $name, $expectedClass ) {
185 $moduleManager = $this->getModuleManager();
186 $moduleManager->addModules( $modules, 'test' );
187
188 // should return the right module
189 $module1 = $moduleManager->getModule( $name, null, false );
190 $this->assertInstanceOf( $expectedClass, $module1 );
191
192 // should pass group check (with caching disabled)
193 $module2 = $moduleManager->getModule( $name, 'test', true );
194 $this->assertNotNull( $module2 );
195
196 // should use cached instance
197 $module3 = $moduleManager->getModule( $name, null, false );
198 $this->assertSame( $module1, $module3 );
199
200 // should not use cached instance if caching is disabled
201 $module4 = $moduleManager->getModule( $name, null, true );
202 $this->assertNotSame( $module1, $module4 );
203 }
204
205 /**
206 * @covers ApiModuleManager::getModule
207 */
208 public function testGetModule_null() {
209 $modules = [
210 'login' => ApiLogin::class,
211 'logout' => ApiLogout::class,
212 ];
213
214 $moduleManager = $this->getModuleManager();
215 $moduleManager->addModules( $modules, 'test' );
216
217 $this->assertNull( $moduleManager->getModule( 'quux' ), 'unknown name' );
218 $this->assertNull( $moduleManager->getModule( 'login', 'bla' ), 'wrong group' );
219 }
220
221 /**
222 * @covers ApiModuleManager::getNames
223 */
224 public function testGetNames() {
225 $fooModules = [
226 'login' => ApiLogin::class,
227 'logout' => ApiLogout::class,
228 ];
229
230 $barModules = [
231 'feedcontributions' => [ 'class' => ApiFeedContributions::class ],
232 'feedrecentchanges' => [ 'class' => ApiFeedRecentChanges::class ],
233 ];
234
235 $moduleManager = $this->getModuleManager();
236 $moduleManager->addModules( $fooModules, 'foo' );
237 $moduleManager->addModules( $barModules, 'bar' );
238
239 $fooNames = $moduleManager->getNames( 'foo' );
240 $this->assertArrayEquals( array_keys( $fooModules ), $fooNames );
241
242 $allNames = $moduleManager->getNames();
243 $allModules = array_merge( $fooModules, $barModules );
244 $this->assertArrayEquals( array_keys( $allModules ), $allNames );
245 }
246
247 /**
248 * @covers ApiModuleManager::getNamesWithClasses
249 */
250 public function testGetNamesWithClasses() {
251 $fooModules = [
252 'login' => ApiLogin::class,
253 'logout' => ApiLogout::class,
254 ];
255
256 $barModules = [
257 'feedcontributions' => [ 'class' => ApiFeedContributions::class ],
258 'feedrecentchanges' => [ 'class' => ApiFeedRecentChanges::class ],
259 ];
260
261 $moduleManager = $this->getModuleManager();
262 $moduleManager->addModules( $fooModules, 'foo' );
263 $moduleManager->addModules( $barModules, 'bar' );
264
265 $fooNamesWithClasses = $moduleManager->getNamesWithClasses( 'foo' );
266 $this->assertArrayEquals( $fooModules, $fooNamesWithClasses );
267
268 $allNamesWithClasses = $moduleManager->getNamesWithClasses();
269 $allModules = array_merge( $fooModules, [
270 'feedcontributions' => ApiFeedContributions::class,
271 'feedrecentchanges' => ApiFeedRecentChanges::class,
272 ] );
273 $this->assertArrayEquals( $allModules, $allNamesWithClasses );
274 }
275
276 /**
277 * @covers ApiModuleManager::getModuleGroup
278 */
279 public function testGetModuleGroup() {
280 $fooModules = [
281 'login' => ApiLogin::class,
282 'logout' => ApiLogout::class,
283 ];
284
285 $barModules = [
286 'feedcontributions' => [ 'class' => ApiFeedContributions::class ],
287 'feedrecentchanges' => [ 'class' => ApiFeedRecentChanges::class ],
288 ];
289
290 $moduleManager = $this->getModuleManager();
291 $moduleManager->addModules( $fooModules, 'foo' );
292 $moduleManager->addModules( $barModules, 'bar' );
293
294 $this->assertEquals( 'foo', $moduleManager->getModuleGroup( 'login' ) );
295 $this->assertEquals( 'bar', $moduleManager->getModuleGroup( 'feedrecentchanges' ) );
296 $this->assertNull( $moduleManager->getModuleGroup( 'quux' ) );
297 }
298
299 /**
300 * @covers ApiModuleManager::getGroups
301 */
302 public function testGetGroups() {
303 $fooModules = [
304 'login' => ApiLogin::class,
305 'logout' => ApiLogout::class,
306 ];
307
308 $barModules = [
309 'feedcontributions' => [ 'class' => ApiFeedContributions::class ],
310 'feedrecentchanges' => [ 'class' => ApiFeedRecentChanges::class ],
311 ];
312
313 $moduleManager = $this->getModuleManager();
314 $moduleManager->addModules( $fooModules, 'foo' );
315 $moduleManager->addModules( $barModules, 'bar' );
316
317 $groups = $moduleManager->getGroups();
318 $this->assertArrayEquals( [ 'foo', 'bar' ], $groups );
319 }
320
321 /**
322 * @covers ApiModuleManager::getClassName
323 */
324 public function testGetClassName() {
325 $fooModules = [
326 'login' => ApiLogin::class,
327 'logout' => ApiLogout::class,
328 ];
329
330 $barModules = [
331 'feedcontributions' => [ 'class' => ApiFeedContributions::class ],
332 'feedrecentchanges' => [ 'class' => ApiFeedRecentChanges::class ],
333 ];
334
335 $moduleManager = $this->getModuleManager();
336 $moduleManager->addModules( $fooModules, 'foo' );
337 $moduleManager->addModules( $barModules, 'bar' );
338
339 $this->assertEquals(
340 ApiLogin::class,
341 $moduleManager->getClassName( 'login' )
342 );
343 $this->assertEquals(
344 ApiLogout::class,
345 $moduleManager->getClassName( 'logout' )
346 );
347 $this->assertEquals(
348 ApiFeedContributions::class,
349 $moduleManager->getClassName( 'feedcontributions' )
350 );
351 $this->assertEquals(
352 ApiFeedRecentChanges::class,
353 $moduleManager->getClassName( 'feedrecentchanges' )
354 );
355 $this->assertFalse(
356 $moduleManager->getClassName( 'nonexistentmodule' )
357 );
358 }
359
360 /**
361 * @expectedException \InvalidArgumentException
362 * @expectedExceptionMessage $spec must define a class name
363 */
364 public function testAddModuleWithIncompleteSpec() {
365 $moduleManager = $this->getModuleManager();
366
367 $moduleManager->addModule(
368 'logout',
369 'action',
370 [
371 'factory' => function ( ApiMain $main, $action ) {
372 return new ApiLogout( $main, $action );
373 },
374 ]
375 );
376 }
377 }